Overlays and feedback
Menu
Click the button. The menu is a native popover.
JSX
<Menu trigger="Actions" label="Key actions">
<MenuItem>Rename</MenuItem>
<MenuItem kbd="R">Rotate key</MenuItem>
<MenuSeparator />
<MenuItem danger>Revoke</MenuItem>
</Menu>HTML
<button type="button" class="ra-btn" popoverTarget="ra-menu-_R_0_" style="anchor-name:--ra-menu-_R_0_">Actions</button><div id="ra-menu-_R_0_" popover="auto" aria-label="Key actions" class="ra-menu" style="position-anchor:--ra-menu-_R_0_"><button type="button" class="ra-menu__item"><span>Rename</span></button><button type="button" class="ra-menu__item"><span>Rotate key</span><kbd class="ra-kbd">R</kbd></button><div role="separator" class="ra-menu__sep"></div><button type="button" class="ra-menu__item ra-menu__item--danger"><span>Revoke</span></button></div>Menu panel
JSX
<MenuPanel label="Endpoints">
<MenuSearch placeholder="Search endpoints" aria-label="Search endpoints" />
<MenuItem hint="1 credit">Email finder</MenuItem>
<MenuItem hint="1 credit">Domain lookup</MenuItem>
<MenuSeparator />
<MenuItem hint="3 credits">Company enrich</MenuItem>
</MenuPanel>HTML
<div class="g-frame" style="max-width:280px"><div role="group" aria-label="Endpoints" class="ra-menu ra-menu--static"><div class="ra-menu__search"><input type="search" class="ra-menu__search-input" placeholder="Search endpoints" aria-label="Search endpoints"/></div><button type="button" class="ra-menu__item"><span>Email finder</span><small class="ra-menu__hint">1 credit</small></button><button type="button" class="ra-menu__item"><span>Domain lookup</span><small class="ra-menu__hint">1 credit</small></button><div role="separator" class="ra-menu__sep"></div><button type="button" class="ra-menu__item"><span>Company enrich</span><small class="ra-menu__hint">3 credits</small></button></div></div>Tooltip
Hover or focus. Pure CSS, driven by data-tip.
JSX
<IconButton label="Add agent" icon={<Plus />} />
<Tooltip label="Live in production" side="bottom">
<button type="button" style={{ all: "unset", cursor: "pointer" }}>
<Pill>Live</Pill>
</button>
</Tooltip>HTML
<div class="g-frame g-frame--row" style="gap:24px;padding:32px 0"><button type="button" class="ra-btn ra-btn--ghost ra-btn--icon ra-tip" aria-label="Add agent" data-tip="Add agent"><svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><path d="M8 3v10M3 8h10"></path></svg></button><span class="ra-tip" data-tip="Live in production" data-side="bottom"><button type="button" style="all:unset;cursor:pointer"><span class="ra-pill">Live</span></button></span></div>Dialog
A native modal dialog. Shown open in place here.
JSX
<Dialog open onClose={() => {}} title="Rename key" footer={<Button onClick={() => {}}>Cancel</Button>
<Button variant="primary" onClick={() => {}}>Save</Button>}>
<Input label="Key name" defaultValue="prod-agent" />
</Dialog>HTML
<dialog class="ra-dialog" aria-labelledby="_R_0_-title" open=""><div class="ra-dialog__panel"><div class="ra-dialog__head"><h2 class="ra-dialog__title" id="_R_0_-title">Rename key</h2><button type="button" class="ra-btn ra-btn--ghost ra-btn--sm ra-btn--icon" aria-label="Close"><svg class="ra-icon ra-icon--sm" viewBox="0 0 24 24" aria-hidden="true"><path d="M18 6 6 18"></path><path d="m6 6 12 12"></path></svg></button></div><div class="ra-dialog__body"><div class="ra-field"><label class="ra-field__label" for="_R_7_">Key name</label><input id="_R_7_" class="ra-input" value="prod-agent"/></div></div><div class="ra-dialog__foot"><button type="button" class="ra-btn">Cancel</button><button type="button" class="ra-btn ra-btn--primary">Save</button></div></div></dialog>Type to confirm
confirmText keeps the confirm button disabled until the name is typed exactly.
JSX
<AlertDialog open title={"Revoke \"prod-agent\"?"} description="Every request using rk_live_••••4f2a fails immediately. This can't be undone." confirmLabel="Revoke key" confirmText="prod-agent" onConfirm={() => {}} onCancel={() => {}} />HTML
<dialog class="ra-dialog ra-dialog--sm" aria-labelledby="_R_0_-title" aria-describedby="_R_0_-desc" open=""><div class="ra-dialog__panel"><div class="ra-dialog__head"><h2 class="ra-dialog__title" id="_R_0_-title">Revoke "prod-agent"?</h2><button type="button" class="ra-btn ra-btn--ghost ra-btn--sm ra-btn--icon" aria-label="Close"><svg class="ra-icon ra-icon--sm" viewBox="0 0 24 24" aria-hidden="true"><path d="M18 6 6 18"></path><path d="m6 6 12 12"></path></svg></button></div><p class="ra-dialog__desc" id="_R_0_-desc">Every request using rk_live_••••4f2a fails immediately. This can't be undone.</p><div class="ra-dialog__body"><div class="ra-field"><label class="ra-field__label" for="_R_7_">Type <b>prod-agent</b> to confirm</label><input id="_R_7_" class="ra-input" data-autofocus="true" autoComplete="off" value=""/></div></div><div class="ra-dialog__foot"><button type="button" class="ra-btn">Cancel</button><button type="button" class="ra-btn ra-btn--danger" disabled="">Revoke key</button></div></div></dialog>Alert dialog
JSX
<AlertDialog open title="Revoke prod-agent?" description="Calls that use this key fail right away. You cannot undo this." confirmLabel="Revoke key" onConfirm={() => {}} onCancel={() => {}} />HTML
<dialog class="ra-dialog ra-dialog--sm" aria-labelledby="_R_0_-title" aria-describedby="_R_0_-desc" open=""><div class="ra-dialog__panel"><div class="ra-dialog__head"><h2 class="ra-dialog__title" id="_R_0_-title">Revoke prod-agent?</h2><button type="button" class="ra-btn ra-btn--ghost ra-btn--sm ra-btn--icon" aria-label="Close"><svg class="ra-icon ra-icon--sm" viewBox="0 0 24 24" aria-hidden="true"><path d="M18 6 6 18"></path><path d="m6 6 12 12"></path></svg></button></div><p class="ra-dialog__desc" id="_R_0_-desc">Calls that use this key fail right away. You cannot undo this.</p><div class="ra-dialog__foot"><button type="button" class="ra-btn" data-autofocus="true">Cancel</button><button type="button" class="ra-btn ra-btn--danger">Revoke key</button></div></div></dialog>Primary alert dialog
JSX
<AlertDialog open tone="primary" title="Raise the rule to 150 cr?" description="Claude Code asks you above 150 cr from now on." confirmLabel="Raise rule" onConfirm={() => {}} onCancel={() => {}} />HTML
<dialog class="ra-dialog ra-dialog--sm" aria-labelledby="_R_0_-title" aria-describedby="_R_0_-desc" open=""><div class="ra-dialog__panel"><div class="ra-dialog__head"><h2 class="ra-dialog__title" id="_R_0_-title">Raise the rule to 150 cr?</h2><button type="button" class="ra-btn ra-btn--ghost ra-btn--sm ra-btn--icon" aria-label="Close"><svg class="ra-icon ra-icon--sm" viewBox="0 0 24 24" aria-hidden="true"><path d="M18 6 6 18"></path><path d="m6 6 12 12"></path></svg></button></div><p class="ra-dialog__desc" id="_R_0_-desc">Claude Code asks you above 150 cr from now on.</p><div class="ra-dialog__foot"><button type="button" class="ra-btn" data-autofocus="true">Cancel</button><button type="button" class="ra-btn ra-btn--primary">Raise rule</button></div></div></dialog>Command palette
Combobox and listbox in a native modal dialog. Shown open in place here.
JSX
<CommandPalette open onClose={() => {}} groups={[
{
label: "Endpoints",
items: [
{
id: "email",
label: "Find work email",
hint: "1 credit",
onSelect: () => {},
},
{
id: "phone",
label: "Find mobile phone",
hint: "10 credits",
onSelect: () => {},
},
{
id: "company",
label: "Company lookup",
onSelect: () => {},
},
],
},
{
label: "Go to",
items: [
{ id: "usage", label: "Usage", onSelect: () => {} },
{
id: "keys",
label: "API keys",
kbd: "G K",
onSelect: () => {},
},
{ id: "billing", label: "Billing", onSelect: () => {} },
],
},
]} />HTML
<dialog class="ra-palette" aria-label="Command menu" open=""><div class="ra-palette__search"><input class="ra-palette__input" role="combobox" aria-expanded="true" aria-controls="_R_0_-list" aria-activedescendant="_R_0_-opt-email" aria-autocomplete="list" placeholder="Search endpoints and pages" value=""/></div><div class="ra-palette__list" role="listbox" id="_R_0_-list"><div class="ra-palette__group" role="group" aria-label="Endpoints"><div class="ra-palette__group-label ra-label" aria-hidden="true">Endpoints</div><div id="_R_0_-opt-email" role="option" class="ra-palette__item" aria-selected="true">Find work email<small>1 credit</small></div><div id="_R_0_-opt-phone" role="option" class="ra-palette__item" aria-selected="false">Find mobile phone<small>10 credits</small></div><div id="_R_0_-opt-company" role="option" class="ra-palette__item" aria-selected="false">Company lookup</div></div><div class="ra-palette__group" role="group" aria-label="Go to"><div class="ra-palette__group-label ra-label" aria-hidden="true">Go to</div><div id="_R_0_-opt-usage" role="option" class="ra-palette__item" aria-selected="false">Usage</div><div id="_R_0_-opt-keys" role="option" class="ra-palette__item" aria-selected="false">API keys<kbd class="ra-kbd">G K</kbd></div><div id="_R_0_-opt-billing" role="option" class="ra-palette__item" aria-selected="false">Billing</div></div></div><div class="ra-palette__foot">↑↓ to move, ↵ to select, Esc to close</div></dialog>Banners
JSX
<div>
<Banner>Sandbox keys return sample data.</Banner>
<Banner tone="ok">Your card was saved.</Banner>
<Banner tone="warn" actions={<Button variant="primary" size="sm" onClick={() => {}}>Add credits</Button>}>2.20 credits left. Calls stop at zero.</Banner>
<Banner tone="err" actions={<Button onClick={() => {}}>Update card</Button>}>Your last payment failed.</Banner>
</div>HTML
<div><div class="ra-banner" role="status"><div class="ra-banner__text"> Sandbox keys return sample data.</div></div><div class="ra-banner ra-banner--ok" role="status"><div class="ra-banner__text"> Your card was saved.</div></div><div class="ra-banner ra-banner--warn" role="status"><div class="ra-banner__text"> 2.20 credits left. Calls stop at zero.</div><div class="ra-banner__actions"><button type="button" class="ra-btn ra-btn--primary ra-btn--sm">Add credits</button></div></div><div class="ra-banner ra-banner--err" role="alert"><div class="ra-banner__text"> Your last payment failed.</div><div class="ra-banner__actions"><button type="button" class="ra-btn">Update card</button></div></div></div>Pass banner
JSX
<Banner tone="pass" title="Enrichment Pass active.">41,820 cr left this month.</Banner>HTML
<div class="ra-banner ra-banner--pass" role="status"><div class="ra-banner__text"><b>Enrichment Pass active.</b> 41,820 cr left this month.</div></div>Dismissible banner
onDismiss adds a close button. A client component supplies the handler.
JSX
<Banner tone="ok" onDismiss={() => {}}>Your card was saved.</Banner>HTML
<div class="ra-banner ra-banner--ok" role="status"><div class="ra-banner__text"> Your card was saved.</div><button type="button" class="ra-btn ra-btn--ghost ra-btn--sm ra-btn--icon ra-banner__dismiss" aria-label="Dismiss"><svg class="ra-icon ra-icon--sm" viewBox="0 0 24 24" aria-hidden="true"><path d="M18 6 6 18"></path><path d="m6 6 12 12"></path></svg></button></div>Toast with Undo
JSX
<div className="ra-toast-zone">
<Toast action={{ label: "Undo", onAction: () => {} }}>Revoked prod-agent</Toast>
</div>HTML
<div class="ra-toast-zone"><div class="ra-toast">Revoked prod-agent<button type="button" class="ra-toast__action">Undo</button></div></div>Toasts
Static toasts in a zone that previews in place. ToastProvider renders the live zone.
JSX
<div className="ra-toast-zone">
<Toast>Key copied</Toast>
<Toast tone="ok">Run saved</Toast>
<Toast tone="err">The provider did not answer</Toast>
</div>HTML
<div class="ra-toast-zone"><div class="ra-toast">Key copied</div><div class="ra-toast ra-toast--ok">Run saved</div><div class="ra-toast ra-toast--err">The provider did not answer</div></div>Empty state
No runs yet
Run your first call from Endpoints. It shows here with its request, response and receipt.
JSX
<EmptyState title="No runs yet" action={<Button variant="primary">Browse endpoints</Button>}>
Run your first call from Endpoints. It shows here with its request, response and receipt.
</EmptyState>HTML
<div class="ra-empty"><h3 class="ra-empty__title">No runs yet</h3><p class="ra-empty__text">Run your first call from Endpoints. It shows here with its request, response and receipt.</p><div class="ra-empty__action"><button type="button" class="ra-btn ra-btn--primary">Browse endpoints</button></div></div>Error state
The provider timed out (504)
You were not charged. Try again, or pick another provider.
JSX
<EmptyState tone="err" title="The provider timed out (504)">You were not charged. Try again, or pick another provider.</EmptyState>HTML
<div class="ra-empty ra-empty--err"><h3 class="ra-empty__title">The provider timed out (504)</h3><p class="ra-empty__text">You were not charged. Try again, or pick another provider.</p></div>Skeleton
JSX
<Skeleton lines={3} />
<Skeleton height="120px" />HTML
<div class="g-frame g-frame--stack" style="gap:16px"><div class="ra-skel-group" aria-busy="true"><span class="ra-sr-only">Loading</span><div class="ra-skel" aria-hidden="true"></div><div class="ra-skel" aria-hidden="true"></div><div class="ra-skel" aria-hidden="true" style="width:60%"></div></div><div class="ra-skel-group" aria-busy="true"><span class="ra-sr-only">Loading</span><div class="ra-skel" aria-hidden="true" style="height:120px"></div></div></div>Hover card: run
Shown open here. In an app it opens on hover or focus.
JSX
<HoverCard defaultOpen trigger={<a href="/runs/run_8f2a91">run_8f2a91</a>}>
<div className="ra-hovercard__title">
LinkedIn job search
<Pill mono style={{ marginLeft: "auto" }}>run_8f2a91</Pill>
</div>
<Row k="Input" v={"\"product designer\" · Bengaluru"} />
<Row k="Result" v="25 rows" />
<Row k="Billed" v="2.5 cr" />
<Row k="Duration" v="1.84s" />
<Row k="When" v="Sep 11, 14:32" />
</HoverCard>HTML
<div class="g-frame" style="min-height:190px"><span class="ra-hovercard"><a href="/runs/run_8f2a91" aria-describedby="_R_0_">run_8f2a91</a><span class="ra-hovercard__card" role="tooltip" id="_R_0_"><div class="ra-hovercard__title">LinkedIn job search<span class="ra-pill ra-pill--mono" style="margin-left:auto">run_8f2a91</span></div><div class="ra-hovercard__row"><span>Input</span><span>"product designer" · Bengaluru</span></div><div class="ra-hovercard__row"><span>Result</span><span>25 rows</span></div><div class="ra-hovercard__row"><span>Billed</span><span>2.5 cr</span></div><div class="ra-hovercard__row"><span>Duration</span><span>1.84s</span></div><div class="ra-hovercard__row"><span>When</span><span>Sep 11, 14:32</span></div></span></span></div>Hover card: endpoint
JSX
<HoverCard defaultOpen trigger={<a href="/endpoints/email_finder">email_finder</a>}>
<div className="ra-hovercard__title">
Email finder
<Pill tone="brand" style={{ marginLeft: "auto" }}>1 cr</Pill>
</div>
<Row k="Pricing" v="per verified email" />
<Row k="Endpoint" v="/email_finder" />
<Row k="On a miss" v="0 cr" />
</HoverCard>HTML
<div class="g-frame" style="min-height:190px"><span class="ra-hovercard"><a href="/endpoints/email_finder" aria-describedby="_R_0_">email_finder</a><span class="ra-hovercard__card" role="tooltip" id="_R_0_"><div class="ra-hovercard__title">Email finder<span class="ra-pill ra-pill--brand" style="margin-left:auto">1 cr</span></div><div class="ra-hovercard__row"><span>Pricing</span><span>per verified email</span></div><div class="ra-hovercard__row"><span>Endpoint</span><span>/email_finder</span></div><div class="ra-hovercard__row"><span>On a miss</span><span>0 cr</span></div></span></span></div>Retry countdown
JSX
<RetryButton seconds={3} onRetry={() => {}} />HTML
<button type="button" class="ra-btn" disabled="">Retry in 3s</button><span class="ra-sr-only" aria-live="polite"></span>Drawer
A side sheet built on Dialog. Shown open in place here.
JSX
<Drawer open onClose={() => {}} title="Run run_8f2a" description="Email finder" footer={<Button onClick={() => {}}>Close</Button>}>
<KeyValue items={[
{ label: "Status", value: "Success" },
{ label: "Credits", value: "1" },
{ label: "Key", value: "Production" },
{ label: "Duration", value: "412 ms", mono: true },
]} />
</Drawer>HTML
<dialog class="ra-dialog ra-drawer ra-drawer--end" aria-labelledby="_R_0_-title" aria-describedby="_R_0_-desc" open=""><div class="ra-dialog__panel"><div class="ra-dialog__head"><h2 class="ra-dialog__title" id="_R_0_-title">Run run_8f2a</h2><button type="button" class="ra-btn ra-btn--ghost ra-btn--sm ra-btn--icon" aria-label="Close"><svg class="ra-icon ra-icon--sm" viewBox="0 0 24 24" aria-hidden="true"><path d="M18 6 6 18"></path><path d="m6 6 12 12"></path></svg></button></div><p class="ra-dialog__desc" id="_R_0_-desc">Email finder</p><div class="ra-dialog__body"><dl class="ra-kv"><div class="ra-kv__row"><dt class="ra-kv__label">Status</dt><dd class="ra-kv__value">Success</dd></div><div class="ra-kv__row"><dt class="ra-kv__label">Credits</dt><dd class="ra-kv__value">1</dd></div><div class="ra-kv__row"><dt class="ra-kv__label">Key</dt><dd class="ra-kv__value">Production</dd></div><div class="ra-kv__row"><dt class="ra-kv__label">Duration</dt><dd class="ra-kv__value ra-kv__value--mono">412 ms</dd></div></dl></div><div class="ra-dialog__foot"><button type="button" class="ra-btn">Close</button></div></div></dialog>Drawer, start side
side="start" pins the sheet to the left edge.
JSX
<Drawer open side="start" onClose={() => {}} title="Filters" footer={<Button onClick={() => {}}>Done</Button>}>
<Input label="Endpoint" defaultValue="Email finder" />
</Drawer>HTML
<dialog class="ra-dialog ra-drawer ra-drawer--start" aria-labelledby="_R_0_-title" open=""><div class="ra-dialog__panel"><div class="ra-dialog__head"><h2 class="ra-dialog__title" id="_R_0_-title">Filters</h2><button type="button" class="ra-btn ra-btn--ghost ra-btn--sm ra-btn--icon" aria-label="Close"><svg class="ra-icon ra-icon--sm" viewBox="0 0 24 24" aria-hidden="true"><path d="M18 6 6 18"></path><path d="m6 6 12 12"></path></svg></button></div><div class="ra-dialog__body"><div class="ra-field"><label class="ra-field__label" for="_R_7_">Endpoint</label><input id="_R_7_" class="ra-input" value="Email finder"/></div></div><div class="ra-dialog__foot"><button type="button" class="ra-btn">Done</button></div></div></dialog>Popover, live
Click the button. A native popover that focuses its first control.
JSX
<Popover label="Rename key" trigger="Rename">
<Input label="Key name" defaultValue="Production" autoFocus />
</Popover>HTML
<button type="button" class="ra-btn" popoverTarget="ra-pop-_R_0_" aria-haspopup="dialog" style="anchor-name:--ra-pop-_R_0_">Rename</button><div id="ra-pop-_R_0_" popover="auto" role="dialog" aria-label="Rename key" class="ra-popover" style="position-anchor:--ra-pop-_R_0_"><div class="ra-field"><label class="ra-field__label" for="_R_5_">Key name</label><input id="_R_5_" class="ra-input" autofocus="" value="Production"/></div></div>Popover
PopoverPanel is the static version.
- Created
- Sep 9
- Last used
- 2 min ago
- Scope
- All endpoints
JSX
<PopoverPanel label="Key details">
<KeyValue items={[
{ label: "Created", value: "Sep 9" },
{ label: "Last used", value: "2 min ago" },
{ label: "Scope", value: "All endpoints" },
]} />
</PopoverPanel>HTML
<div class="g-frame" style="max-width:260px"><div role="dialog" aria-label="Key details" class="ra-popover ra-popover--static"><dl class="ra-kv"><div class="ra-kv__row"><dt class="ra-kv__label">Created</dt><dd class="ra-kv__value">Sep 9</dd></div><div class="ra-kv__row"><dt class="ra-kv__label">Last used</dt><dd class="ra-kv__value">2 min ago</dd></div><div class="ra-kv__row"><dt class="ra-kv__label">Scope</dt><dd class="ra-kv__value">All endpoints</dd></div></dl></div></div>Progress
JSX
<Progress label="Bulk run, 30 of 120 rows" value={30} max={120} />
<Progress label="Credits used, 85 of 100" value={85} tone="warn" />
<Progress label="Quota used, 100 of 100" value={100} tone="err" />
<Progress label="Uploading" />HTML
<div class="g-frame g-frame--md g-frame--stack" style="gap:16px"><div class="ra-progress" role="progressbar" aria-label="Bulk run, 30 of 120 rows" aria-valuemin="0" aria-valuemax="120" aria-valuenow="30"><i class="ra-progress__fill" style="width:25%"></i></div><div class="ra-progress ra-progress--warn" role="progressbar" aria-label="Credits used, 85 of 100" aria-valuemin="0" aria-valuemax="100" aria-valuenow="85"><i class="ra-progress__fill" style="width:85%"></i></div><div class="ra-progress ra-progress--err" role="progressbar" aria-label="Quota used, 100 of 100" aria-valuemin="0" aria-valuemax="100" aria-valuenow="100"><i class="ra-progress__fill" style="width:100%"></i></div><div class="ra-progress ra-progress--indeterminate" role="progressbar" aria-label="Uploading"><i class="ra-progress__fill"></i></div></div>Spinner
JSX
<Spinner size="sm" label="Loading results" />
<Spinner />HTML
<div class="g-frame g-frame--row" style="gap:16px;flex-wrap:nowrap"><span class="ra-spinner ra-spinner--sm" role="status"><span class="ra-sr-only">Loading results</span></span><span class="ra-spinner" role="status"><span class="ra-sr-only">Loading</span></span></div>