Skip to content
Component installs need the registry setup
VegaStack Design

Record Chip

A picker chip that shows which record something belongs to — icon, name and ▾ — with a ↗ link to that record.

Status
stable
Since
0.23.10
Accessibility pattern
picker button plus a named link

Last updated

Install

Add Record Chip from the VegaStack registry. The CLI verifies the item's integrity hash before writing it.

pnpm dlx shadcn@latest add @vegastack/record-chip

The same command installs the registry items it composes: @vegastack/button, @vegastack/popover.

Usage

import { RecordChip } from "@/components/ui/record-chip";

<PopoverTrigger
  render={
    <RecordChip
      icon={<Building2 />}
      value={customer?.name}
      placeholder="Add customer"
      href={customer ? `/customers/${customer.id}` : undefined}
      linkLabel={`Open ${customer?.name}`}
      renderLink={(props) => <Link {...props} />}
    />
  }
/>;

Every prop not listed below — and the ref — goes to the picker button, so the chip drops into any trigger's render (Popover, DropdownMenu, Combobox).

Anatomy

RecordChip — data-slot="record-chip" | "record-chip-trigger"
SplitChip — data-slot="split-chip"
SplitChipButton — data-slot="split-chip-button"
SplitChipSeparator — data-slot="split-chip-separator"
RecordChipMenu — data-slot="record-chip-menu"

Examples

Customer and project

A customer chip, and a project chip that appears once a customer is set. An empty chip has a dashed border and the placeholder; a set chip adds the ↗ link to the record.

Split chip anatomy

RecordChip is built on SplitChip, exported from the same file, for any pill that holds a main action plus a secondary icon action. The pill carries one shared p-0.5 inset, and every segment is 24px tall and rounded-full, so each hover or open background sits the same 2px from the border on every side. Segments are divided by SplitChipSeparator.

import {
  SplitChip,
  SplitChipButton,
  SplitChipSeparator,
  splitChipIconActionClassName,
} from "@/components/ui/record-chip";

<SplitChip>
  <SplitChipButton onClick={pick}>
    Acme <ChevronDown />
  </SplitChipButton>
  <SplitChipSeparator />
  <Link
    href="/customers/acme"
    aria-label="Open Acme"
    className={splitChipIconActionClassName}
  >
    <ArrowUpRight />
  </Link>
</SplitChip>;

Do not add padding, margins or heights to the segments — the inset belongs to the pill.

Picker menu

RecordChipMenu is the popover a pill opens: start-aligned with no inner padding, 288px for a searchable Command list (width="list") or as wide as a Calendar (width="fit").

API Reference

PropTypeDefaultDescription
hrefstring—Opens the linked record. With a value, a ↗ link sits after the picker.
iconReact.ReactNode—The record type's icon (a building for a customer, a folder for a project).
linkLabelstring"Open"Accessible name of the ↗ link.
placeholderReact.ReactNode"Select"Shown when there is no value, e.g. "Add customer". null shows the icon alone (no text, no ▾) — an unset pill in a dense row; name the button with aria-label.
renderLink((props: { href: string; className: string; "aria-label": string; children: React.ReactNode; }) => React.ReactNode)a plain `<a>`Renders the ↗ link — pass your router's link for client navigation.
valueReact.ReactNode—The linked record's name. Empty shows placeholder in the muted ink.

Data attributes and CSS variables on RecordChip

AttributeValues
data-empty""
data-slot"record-chip" | "record-chip-trigger"

Accessibility

  • The picker is a button; the trigger it is rendered into adds aria-expanded and aria-haspopup. Give it an aria-label such as "Customer: Acme" when the icon is the only thing that says which kind of record it is.
  • The ↗ link is a separate tab stop named by linkLabel ("Open Acme").
ContractStates tested
Behaviourdefault, empty, linked, disabled
Accessibilitylabeled
Visualdefault, empty, linked, disabled

Do / Don't

Do
Use RecordChip in a record's header to link it to its customer or project, with a jump to that record.
Don't
Use it for free-form tags (Chip) or inside a form with a visible label (Combobox, Select).

On this page