Qure UI
Components

Action Bar

The footer of a modal or panel — the actions, and a line of context beside them.

Signing is final. An amendment leaves a visible trail.

'use client'import { ActionBar, ActionBarActions, ActionBarNote } from '@/registry/qure/ui/action-bar'import { Button } from '@/registry/qure/ui/button'export default function ActionBarDemo() {  return (    <ActionBar className="max-w-xl rounded-md border">      <ActionBarNote>Signing is final. An amendment leaves a visible trail.</ActionBarNote>      <ActionBarActions>        <Button variant="tertiary">Cancel</Button>        <Button>Sign report</Button>      </ActionBarActions>    </ActionBar>  )}

Installation

npx shadcn@latest add https://qure-ui.qure.ai/r/action-bar.json

Usage

import { ActionBar, ActionBarActions, ActionBarNote } from '@/components/ui/action-bar'
<ActionBar>
  <ActionBarNote>Signing is final.</ActionBarNote>
  <ActionBarActions>
    <Button variant="tertiary">Cancel</Button>
    <Button>Sign report</Button>
  </ActionBarActions>
</ActionBar>

This is one of the components with no shadcn equivalent. It comes from the Qure design system, and pairs with Header Bar to frame a modal, a drawer or a form panel.

Where the primary action goes

Right-most. Cancel and anything else sit to its left.

This is the platform convention on the web and on Windows, and it is the one the design system chose. It is worth knowing that macOS native dialogs do the opposite, so if a Mac app looks "correct" and this looks wrong, the Mac app is not the reference — do not swap them to match it.

The note

Last saved 09:14, two minutes ago.

'use client'import { ActionBar, ActionBarActions, ActionBarNote } from '@/registry/qure/ui/action-bar'import { Button } from '@/registry/qure/ui/button'/** * With and without. The note is a slot rather than a variant — Figma calls the * axis "with note" / "without note", but that is just whether you passed one. */export default function ActionBarNoteExample() {  return (    <div className="flex w-full max-w-xl flex-col gap-4">      <ActionBar className="rounded-md border">        <ActionBarActions>          <Button variant="tertiary">Cancel</Button>          <Button>Save draft</Button>        </ActionBarActions>      </ActionBar>      <ActionBar className="rounded-md border">        <ActionBarNote>Last saved 09:14, two minutes ago.</ActionBarNote>        <ActionBarActions>          <Button variant="tertiary">Cancel</Button>          <Button>Save draft</Button>        </ActionBarActions>      </ActionBar>    </div>  )}

Figma calls the axis "with note" and "without note", but that is only whether you passed one, so here it is a slot rather than a variant.

ActionBarNote comes before the actions in the DOM as well as on screen, so a screen reader reaches the caveat before the button it is a caveat about. Use it for the thing someone would want to know before committing — that an action cannot be undone, when the draft last saved, how many records are affected.

A destructive action

The draft and its 2 annotations are removed.

'use client'import { ActionBar, ActionBarActions, ActionBarNote } from '@/registry/qure/ui/action-bar'import { Button } from '@/registry/qure/ui/button'/** * A destructive primary. It still sits right-most, because position means * "this is the action of the bar" and not "this one is safe" — the colour is * what says it is dangerous, and moving it would only make it harder to find. */export default function ActionBarDestructive() {  return (    <ActionBar className="max-w-xl rounded-md border">      <ActionBarNote>The draft and its 2 annotations are removed.</ActionBarNote>      <ActionBarActions>        <Button variant="tertiary">Keep editing</Button>        <Button variant="destructive">Discard draft</Button>      </ActionBarActions>    </ActionBar>  )}

A destructive primary still sits right-most. Position means "this is the action of the bar", not "this one is safe"; the colour is what says it is dangerous, and moving it only makes it harder to find while doing nothing to make it harder to press.

If the consequence is severe enough that a misclick matters, that is an argument for Alert Dialog rather than for rearranging the footer.

In a modal

Share this study

A link to ACC-482913 will be sent to the referring clinician. The link expires in 7 days and access is recorded against your account.

Access is audited.

'use client'import { XIcon } from 'lucide-react'import { ActionBar, ActionBarActions, ActionBarNote } from '@/registry/qure/ui/action-bar'import { Button } from '@/registry/qure/ui/button'import { HeaderBar, HeaderBarActions, HeaderBarTitle } from '@/registry/qure/ui/header-bar'/** * The two bars are what the Figma "Modal — Dialogue / Notification / * Interactive" frames are made of: a header bar, a body, an action bar, at one * of four widths. They are compositions rather than components, which is why * there is no Modal in this library beyond Dialog. */export default function ActionBarModal() {  return (    <div className="bg-muted w-full max-w-[480px] overflow-hidden rounded-2xl border">      <HeaderBar size="md" divider>        <HeaderBarTitle>Share this study</HeaderBarTitle>        <HeaderBarActions>          <Button variant="tertiary" size="icon-sm" aria-label="Close">            <XIcon />          </Button>        </HeaderBarActions>      </HeaderBar>      <div className="text-body-small text-muted-foreground bg-background p-4">        A link to ACC-482913 will be sent to the referring clinician. The link expires in 7 days        and access is recorded against your account.      </div>      <ActionBar>        <ActionBarNote>Access is audited.</ActionBarNote>        <ActionBarActions>          <Button variant="tertiary">Cancel</Button>          <Button>Send link</Button>        </ActionBarActions>      </ActionBar>    </div>  )}

The two bars are what Figma's "Modal — Dialogue / Notification / Interactive" frames are made of: a header bar, a body, an action bar, at one of four widths. They are compositions rather than components, which is why this library has no Modal beyond Dialog.

<DialogContent className="max-w-[480px] p-0">
  <HeaderBar size="md" divider>…</HeaderBar>
  <div className="p-4">…</div>
  <ActionBar>…</ActionBar>
</DialogContent>

p-0 on the content is the part people miss — the dialog's own padding would sit inside the bars and pull them off the edges, and the bars carry their own.

API Reference

ActionBar

PropTypeDefaultDescription
dividerbooleantrueA 0.5px hairline along the top edge. On by default, since it usually caps a scrolling body.

ActionBarNote renders a <p> and ActionBarActions a <div>. With no note present the bar right-aligns the actions on its own.

On this page