Recent Strip
One row of the records a person opened last, as compact cards in a sideways strip with edge fades and arrow keys, and a single line of chips on a phone.
- Status
- Since
0.25.90- Accessibility pattern
- Named region; one Tab stop, arrow keys between cards
Last updated
Recent
Install
Configure registry credentials first using the Quickstart. Before copying this item or any transitive registry dependency, verify the signed manifest and save the exact bytes for Recent Strip before installation. Retain the digest printed by this command.
pnpm exec vegastack-design verify recent-stripInstall with the pinned shadcn CLI. Bare shadcn does not verify VegaStack signature or integrity.
pnpm dlx shadcn@4.21.0 add @vegastack/recent-stripRun the exact offline --post-write command printed by the preflight, using its saved item path and independently retained --expected-integrity digest. Use the saved preflight for every transitive registry dependency too; stop on any mismatch before using the components.
The same command installs the registry items it composes: @vegastack/button, @vegastack/collapsible, @vegastack/skeleton, @vegastack/use-list-nav, @vegastack/use-media-query.
Usage
import { RecentStrip } from "@/components/ui/recent-strip";
<RecentStrip
label="Recent"
collapsible
open={recentOpen}
onOpenChange={saveRecentOpen}
linkRender={<Link href="" />}
items={recents.map((r) => ({
href: r.href,
icon: <KindIcon kind={r.kind} />,
title: r.title,
meta: `${r.kindLabel} · ${r.when}`,
}))}
/>;One row of the records a person opened last, so they can jump back in without the main list being
pushed down a screen. Up to max (six) compact cards — an icon tile, the title and one meta line —
sit in a strip that scrolls sideways, with fades at the clipped edges and, on a mouse, buttons at
the ends. On a narrow strip (under 28rem of its own width, so a phone) the cards become a single
line of chips. The strip is one Tab stop; ← and → move between the cards.
Scope
- Owns: the heading and its fold toggle, the strip's layout, scroll fades and end buttons, the card and chip shapes, the roving tab stop, the loading skeleton, and rendering nothing when empty.
- Does not own: which records are recent, their order, their icons or meta text, or remembering
whether the strip is folded — pass
open/onOpenChangeand keep it where the host keeps preferences. - Compose with: a router link through
linkRender; a formatted time in themetatext (the card is one link, sometais plain text, never a control); the list it sits above (DataList).
Examples
Recent row
Six cards; the strip scrolls past the frame with fades at the clipped edge.
Recent
Collapsible
collapsible makes the heading a toggle that folds the strip to its heading row. Control it with
open/onOpenChange to remember the choice.
On a phone
Under 28rem of the strip's own width the cards become one line of chips — the icon and the title — so the list below starts in the first screen.
Recent
Loading and empty
loading keeps the heading and shows skeleton cards of the same shape. With no records the strip
renders nothing, unless emptyState gives it a line to show.
Recent
Jump back in
API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
collapsible | boolean | false | The heading becomes a toggle that folds the strip away to its heading row. |
defaultOpen | boolean | true | Whether a collapsible strip starts open (uncontrolled). |
emptyState | React.ReactNode | — | What to show under the heading when there are no records. Without it an empty strip renders nothing at all. |
headingRender | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | <h2 /> | The heading element (<h3 /> under an h2 section). Its children are the label (or the
toggle). |
items | RecentStripItem[] | [] | The records, most recent first. Only the first max render. |
label | string | "Recent" | The strip's heading — and the toggle's name when it is collapsible. |
linkRender | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | <a /> | The element each card renders as — a router link (<Link />); it receives href, the card's
classes and its content. |
loading | boolean | false | Shows skeleton cards of the same shape (the heading stays) while the records load. |
max | number | 6 | The most cards the strip shows. |
onOpenChange | ((open: boolean) => void) | — | Called when the toggle opens or folds the strip — persist it to remember the choice. |
open | boolean | — | Whether a collapsible strip is open (controlled). Pair with onOpenChange. |
scrollBackLabel | string | "Scroll back" | The name of the mouse-only button that scrolls back. |
scrollForwardLabel | string | "Scroll forward" | The name of the mouse-only button that scrolls forward. |
Data attributes and CSS variables on RecentStrip
| Attribute | Values |
|---|---|
data-loading | "" |
data-slot | "recent-strip" | "recent-strip-content" | "recent-strip-empty" | "recent-strip-toggle" |
data-state | "closed" | "open" |
RecentStripItem
| Prop | Type | Default | Description |
|---|---|---|---|
href* | string | — | Where the card goes — rendered through linkRender (default <a />). |
title* | string | — | The record's name — the link's accessible name. |
icon | React.ReactNode | — | The record's kind as a glyph (decorative). |
id | string | the item's `href` | Stable key. |
meta | string | — | One quiet line under the title on a card ("Page · 2h ago") — plain text, since the whole card is one link; it describes the link and is hidden on the phone's chips. |
Accessibility
- The strip is a region named by its heading; the cards are a list of links, each named by its title and meta line. Icons are decorative.
- One Tab stop for the whole strip: the arrow keys move between the cards, and focusing a card scrolls it into view.
- A collapsible heading is a button with
aria-expanded, inside the heading element (headingRender, anh2by default). - The scroll buttons at the ends are for the mouse only — out of the tab order and hidden from assistive technology, which reaches every card with the keys.
| Key | Action |
|---|---|
| Tab | Enters the strip at its current card |
| ← / → | Moves to the previous or next card |
| Home / End | Moves to the first or last card |
| Enter | Opens the card |
| Enter / Space | On the heading, folds or opens it |
| Contract | States tested |
|---|---|
| Behaviour | default, max, collapsed, loading, empty, empty-state, link-render, keyboard-roving, overflow |
| Accessibility | labeled-region, heading, keyboard, single-tab-stop, browser-accessibility-test |
| Visual | default, hover, focus, collapsed, loading, chips |