# QR code, Drawer, Card, and more

Released 23 Sept 2026. [Components 2.14.0](https://github.com/TicketSolutionsPtyLtd/roadie/blob/main/packages/components/CHANGELOG.md#2140), [Core 2.9.0](https://github.com/TicketSolutionsPtyLtd/roadie/blob/main/packages/core/CHANGELOG.md#290), and [Widgets 3.6.1](https://github.com/TicketSolutionsPtyLtd/roadie/blob/main/packages/widgets/CHANGELOG.md#361)

8 additions, 5 changes, and 4 fixes.

## Highlights

- **QR code**: A QR code for scanning tickets at the gate. See [QR code](https://ticketsolutionsptyltd.github.io/roadie/components/qr-code.md).

## New

- `Card.Footer` reads `--card-footer-size` when it's a side column, with `direction='horizontal'` or a split `direction='auto'`.

  See [Card](https://ticketsolutionsptyltd.github.io/roadie/components/card.md).

  Set it once on a list so every card's side column, and a ticket's perforation along it, lines up whatever each footer holds. It's a minimum, so a wider footer still grows rather than overflowing, and a stacked footer ignores it.
- Add `Card.Link`, the card's main link, for a card that also holds other actions.

  See [Card](https://ticketsolutionsptyltd.github.io/roadie/components/card.md).

  Wrap the title in it. It covers the card, so a click anywhere follows it, while other links and buttons in the card stay clickable above it. The card takes its hover, press and focus states from the link, for plain and ticket cards and every emphasis, so apps no longer restate them. Screen readers hear a short link named by its own text rather than the whole card. It routes `href` like every other Roadie link.

  On a ticket card in a browser without `corner-shape` (Firefox today), the
  footer's plain text doesn't follow the link; its own links still work.
- Add `variant='ticket'` to `Card`.

  See [Card](https://ticketsolutionsptyltd.github.io/roadie/components/card.md).

  It cuts a real notch into each side where the body meets `Card.Footer`, with a perforated line between them, and works with every emphasis.

  Add `direction` to `Card`. It lays out any card's parts: `vertical` (the
  default) stacks them, `horizontal` gives `Card.Footer` a column of its own
  beside the rest of the card, and `auto` stacks below 30rem and splits into two
  columns at or above it. On a ticket, the notches and the perforation follow
  whichever layout is in effect.
- Add `emphasis` to `Drawer` and `Dialog`: how much the overlay takes over the page behind it.

  See [Drawer](https://ticketsolutionsptyltd.github.io/roadie/components/drawer.md), [Dialog](https://ticketsolutionsptyltd.github.io/roadie/components/dialog.md).

  `normal` dims and blurs the page, `subtle` tints it and leaves it readable, and `subtler` leaves it clear while a click outside still dismisses. A small (`size='sm'`) top or bottom drawer defaults to `subtle`, because it peeks over its page; every other drawer and every dialog defaults to `normal`.

  Core adds `emphasis-overlay-subtle`, and `emphasis-overlay` now drops its blur
  under `prefers-reduced-transparency` and carries the `-webkit-` prefix.
- Add `size` to an inspector `Pane`: `sm` (14rem, the default), `md` (20rem) or `lg` (24rem).

  See [Pane](https://ticketsolutionsptyltd.github.io/roadie/components/pane.md).

  Each size has its own thresholds, so the stack's panes keep their minimum widths beside it and `pane-inspector-yielded:` flips at the right width. Use `size` rather than widening the column with a class, which leaves the thresholds assuming 14rem.
- Add `measure` to `Pane`: `full` (the default), `narrow` (24rem, for forms), `readable` (65ch of the pane's text) or `wide` (56rem).

  See [Pane](https://ticketsolutionsptyltd.github.io/roadie/components/pane.md).

  It caps the body and the header's title while the header and footer still span the column. `measureAlign='start'` holds the capped content to the start instead of centring it.
- Add `QRCode` for scanning tickets at the gate, from `@oztix/roadie-components/qr-code`.

  See [QR code](https://ticketsolutionsptyltd.github.io/roadie/components/qr-code.md).

  It encodes `value` at error correction level H and, by default, puts the Oztix mark on a dark 5×5-module tile in the centre. Pass `children` to use your own mark, or `branded={false}` for a plain code. It's always dark on white, whatever the theme or intent, and has no hooks, so it renders in server components.
- Add `is-interactive-within`, for a surface whose main link sits inside it, such as a card that also holds other actions.

  Mark the link with `data-interactive-target`. Its overlay covers the surface, so a click anywhere follows it, and other links, buttons and fields sit above it and stay clickable. The surface takes the same hover, press and focus states as `is-interactive` while its main link is hovered, pressed or focused, from the same emphasis rules, so the values live in one place. It does nothing until a target is present.

  `is-interactive` now reads its transition list from `--interactive-transition`,
  which both utilities share.

## Changed

- A `Drawer.Close` inside `Drawer.Header` now takes the top-left corner above the title, as far from the top edge as from the side, wherever it's written.

  See [Drawer](https://ticketsolutionsptyltd.github.io/roadie/components/drawer.md).

  Render it as a `normal` `IconButton` named "Close". The Drawer docs gain guidelines for naming a drawer, placing Close, when a drawer needs one, and keeping a second Close out of the footer.
- Top and bottom drawers now run edge to edge on a phone and, from `sm` up, stop at `max-w-xl`, centred, floating `--spacing(2)` off their edge with every corner rounded: the same shape as the cart drawer.

  Remove any width, margin or radius classes an app added to get this.

  Every drawer now rounds at `rounded-4xl`, the new Sheet tier on the Shape
  foundation, whichever side it comes from. The edge it's attached to stays
  square.

  `Drawer.Body` now scrolls in `ScrollArea`, so drawers use Roadie's scrollbar.
  It is still Base UI's drawer content, so a drag in a scrolled body scrolls it
  rather than dismissing. A `className` on it still styles the content, as
  before.

  Core's `motion-drawer` reads `--drawer-float`, so a surface held off its edge
  slides fully clear.
- `Drawer` sizes on the top and bottom are now fixed heights, so a sheet holds still while its content changes.

  See [Drawer](https://ticketsolutionsptyltd.github.io/roadie/components/drawer.md).

  Each is a share of the space the drawer can use. That space leaves out the far edge's safe area and a gap, like an iOS large sheet, and in a wider window the float off the near edge. `sm` is half of it, `md` three quarters and `lg` all of it. The new `fit` size follows the content up to all of it, and is the default for top and bottom drawers. Side drawers keep `md` as their default, and `fit` there sizes to the content's width up to the `lg` width. Remove any `h-*` class an app added to hold a drawer's height.
- `Pane.Body` now renders a `<div>` that fills the height the header leaves, and takes `className` and the other div props.

  See [Pane](https://ticketsolutionsptyltd.github.io/roadie/components/pane.md).

  A band or background on it reaches the pane's bottom edge, and a child with `grow` inside a `flex flex-col` body does too, so apps no longer need to restyle the pane's scroll content. A pane without a `Pane.Body` keeps its content height, as before.
- An inspector `Pane` now moves its content into a bottom drawer when its column yields, so apps no longer write the content twice.

  See [Pane](https://ticketsolutionsptyltd.github.io/roadie/components/pane.md).

  Place a `Pane.InspectorTrigger` anywhere in the same `Navigator`: it shows only while the column has yielded and opens the drawer, which takes its name from the inspector's `aria-label` and keeps the page readable behind it.

  `reveal` on the inspector says its content should be seen. While the column
  shows, it already is; once the column has yielded, `reveal` opens the drawer.
  `onRevealChange` reports the trigger opening it and people dismissing it.

  The drawer is a fixed `lg` sheet, so filtering the content can't resize it
  under the user's thumb. `drawerSize` on the inspector picks another Drawer
  size.

  In the drawer, the inspector's own `Pane.Header` shows a Close in its top-left
  corner, 24px from the drawer's top and side, and casts the drawer's scroll
  shadow. Content without a `Pane.Header` gets a header holding just the Close.
  The drawer sets `--pane-surface` to its raised fill, so sticky chrome inside
  it mixes against the right colour.

  `pane-inspector-yielded:` also applies to the inspector's own content once it's
  in the drawer, so content can adapt to where it renders.

## Fixed

- A `Card` with `direction='auto'` is now a container named `card`, so its children can use `@min-[30rem]/card:` and know it resolves against the card rather than a container further up.

  See [Card](https://ticketsolutionsptyltd.github.io/roadie/components/card.md).
- `Drawer.Handle` now uses the divider colour, so it shows on the drawer's floating surface in light and dark mode.

  See [Drawer](https://ticketsolutionsptyltd.github.io/roadie/components/drawer.md).

  It used the sunken fill, which sat a single step off the surface in light mode and read as missing.
- `Drawer.Header` and `Drawer.Footer` cast a shadow over the body while it scrolls beneath them, so a long list reads as passing under the header and footer rather than being cut off.

  See [Drawer](https://ticketsolutionsptyltd.github.io/roadie/components/drawer.md).

  Each shadow fades out when there's nothing left to scroll on its side.
- On the phone tab bar with a pinned item, the tabs now start at the leading edge instead of centring, and both the tabs and the pinned circle sit 1rem in from the edges, where the circles land when the bar collapses on scroll.
