Skip to content
Component installs need the registry setup
VegaStack Design

Block Header

A live block's header row in a page — icon · title · View ▾ · Filter · More · ↗ Open — with an empty state that hosts the source picker.

Status
stable
Since
0.25.89
Accessibility pattern
⋯ menu and Open link named; picker named by the host

Last updated

QA fixtures

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 Block Header before installation. Retain the digest printed by this command.

pnpm exec vegastack-design verify block-header

Install with the pinned shadcn CLI. Bare shadcn does not verify VegaStack signature or integrity.

pnpm dlx shadcn@4.21.0 add @vegastack/block-header

Run 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/dropdown-menu.

Usage

import {
  BlockHeader,
  BlockHeaderButton,
  BlockHeaderOpen,
} from "@/components/ui/block-header";

<DataGrid
  embedded
  toolbar={
    <BlockHeader
      icon={<Table2 />}
      title={table.name}
      menu={<DropdownMenuItem onClick={remove}>Remove block</DropdownMenuItem>}
      open={<BlockHeaderOpen render={<Link href={table.href} />} />}
    >
      <ViewMenu trigger={<BlockHeaderButton />} />
      <FilterPopover trigger={<BlockHeaderButton />} />
    </BlockHeader>
  }
  {...grid}
/>;

The one header row of a live block inside a page — a table view, a task list, any block that shows records from somewhere else. Left to right: the block's kind as an icon, what it shows, its controls (BlockHeaderButtons that open the host's View and Filter popovers), the ⋯ menu and ↗ Open, a link to the source's own page. A block with no source yet passes picker instead: it sits where the title will be ("Pick a table…"), so a block inserts at once and is set up where it sits rather than in a dialog first.

Scope

  • Owns: the row's layout, the ⋯ menu trigger, the Open link's look, the empty state's place for a picker, wrapping on a narrow block.
  • Does not own: the source picker, the View and Filter popovers, or what they change — those are the host's. Nor the block's frame: DataGrid embedded rules the header off as its top, a task list block puts it over its rows.
  • Compose with: DataGrid embedded as its toolbar; a DropdownMenuTrigger or PopoverTrigger with render={<BlockHeaderButton />}.

Anatomy

BlockHeader — data-slot="block-header" | "block-header-actions" | "block-header-controls" | "block-header-icon" | "block-header-menu" | "block-header-picker" | "block-header-title"
BlockHeaderButton — data-slot="block-header-button"
BlockHeaderOpen

Examples

Table block

The title truncates; the controls follow it, and the ⋯ menu and Open sit at the end.

QA fixtures

Before a source is picked

picker replaces the title and the controls. Pick a table in the preview: the header becomes the ready row; Change table in ⋯ brings the picker back.

Task list block, and a narrow column

The same header serves a task list. In a narrow block the controls wrap under the title and, under 20rem, Open shows its icon alone (its label stays the link's name).

Tasks · My open
Tasks · Assigned to me in this space

API Reference

BlockHeader

PropTypeDefaultDescription
childrenReact.ReactNode—The block's controls after the title — BlockHeaderButtons such as View ▾ and Filter. Hidden while picker shows.
iconReact.ReactNode—The block's kind, as an icon (a table, a task list). Decorative.
menuReact.ReactNode—Items for the ⋯ menu (DropdownMenuItems) — Copy link, Remove block. No menu without it.
menuLabelstring"Block actions"The ⋯ trigger's accessible name.
openReact.ReactNode—The ↗ Open link at the end — a BlockHeaderOpen to the source's own page.
pickerReact.ReactNode—The empty state: a picker for the block's source ("Pick a table…"), shown in place of the title and the controls. Pass it only while the block has no source.
titleReact.ReactNode—What the block shows — the source's name ("QA fixtures", "Tasks · My open").

Data attributes and CSS variables on BlockHeader

AttributeValues
data-slot"block-header" | "block-header-actions" | "block-header-controls" | "block-header-icon" | "block-header-menu" | "block-header-picker" | "block-header-title"
data-state"empty" | "ready"

BlockHeaderButton

BlockHeaderButton takes Button's props: a small quiet ghost button in the muted ink.

BlockHeaderOpen

PropTypeDefaultDescription
labelstring"Open"The visible label — and the accessible name when the block is too narrow to show it.
renderReact.ReactElement<unknown, string | React.JSXElementConstructor<any>><a />The link element — a router link such as <Link href="/tables/qa" />. It receives the classes, the icon and the label; this component's own href and handlers win over the template's (handlers run both).

Accessibility

  • The icon is decorative; the title is plain text — name the block's content (the grid's aria-label, the task list's label) for assistive technology.
  • The ⋯ trigger is named by menuLabel ("Block actions").
  • Open is a real link, so it opens in a new tab with a modified click; on a narrow block its label is visually hidden but still names it.
  • The picker is the host's control and carries its own name.
KeyAction
TabMoves through the controls, ⋯ and Open
Enter / SpaceOpens a control's popover or the menu
EscapeCloses the open popover or menu
ContractStates tested
Behaviourdefault, empty, menu-open, narrow
Accessibilitylabeled, keyboard, browser-accessibility-test
Visualdefault, hover, focus, open, empty

Do / Don't

Do
Insert a block at once with the picker in its header, and keep View, Filter and ⋯ in the same row for every kind of block.
Don't
Open a configuration dialog before the block exists, or give the table block and the task list block different headers.

On this page