ComponentsData display

Record chip

Every reference to a record, in a cell, the details rail, a card or Flo's text. The mark says what the record is; the name says which one.

Playground

Change the controls to try each prop. The code under the preview updates as you go and lists only the props you changed; copy it into your page.

Maya Chen
States
import { RecordChip } from '@/ui/record-chip';<RecordChip name="Maya Chen" type="candidate" />

Marks

The mark comes from the record's type. Companies are square: their logo, or their first letter on the tile. People are round: their photo or initials. A Job wears its company's logo when it has one. A change Flo proposed shows Flo's mark. Every other record is its 12px icon on the tile.

Company, logoCompany, letterPersonJobApplicationPlacementTargetMeetingTaskFlo review
import { RecordMark, type RecordType } from '@/ui/record-chip';

const marks: { type: RecordType; name: string; label: string; src?: string }[] = [
  { type: 'company', name: 'Halcyon Bank', label: 'Company, logo', src: '/examples/halcyon-bank.svg' },
  { type: 'company', name: 'Northwind Labs', label: 'Company, letter' },
  { type: 'candidate', name: 'Maya Chen', label: 'Person' },
  { type: 'job', name: 'Senior Data Engineer', label: 'Job' },
  { type: 'application', name: 'Maya Chen at Halcyon Bank', label: 'Application' },
  { type: 'placement', name: 'Maya Chen at Halcyon Bank', label: 'Placement' },
  { type: 'target', name: 'Fintech data leads', label: 'Target' },
  { type: 'interaction', name: 'Call with Sara Lee', label: 'Meeting' },
  { type: 'task', name: 'Send Sara the shortlist', label: 'Task' },
  { type: 'review', name: 'Move Maya to CV sent', label: 'Flo review' },
];

export default function RecordChipMarks() {
  return (
    <div className="flex flex-wrap items-start gap-300">
      {marks.map((mark) => (
        <span key={mark.label} className="flex flex-col items-center gap-100 text-body-small leading-body-small font-medium text-text-subtle">
          <RecordMark type={mark.type} name={mark.name} src={mark.src} />
          {mark.label}
        </span>
      ))}
    </div>
  );
}

Pill

A reference to another record: in the details rail, a cell that points elsewhere, a peek's identity line. 24px tall with a 6px radius and a 1px edge. With href it is a link; hover and press fill it.

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

export default function RecordChipPill() {
  return (
    <div className="flex flex-wrap items-center gap-100">
      <RecordChip type="candidate" name="Maya Chen" href="#maya-chen" />
      <RecordChip type="job" name="Senior Data Engineer" src="/examples/halcyon-bank.svg" href="#senior-data-engineer" />
      <RecordChip type="company" name="Northwind Labs" href="#northwind-labs" />
      <RecordChip type="placement" name="Maya Chen at Halcyon Bank" href="#placement" />
    </div>
  );
}

Plain, in a row's first column

The row's own name. No edge, because the row already opens it; the name underlines on hover. In a table cell, cell takes the link out of the tab order, since the grid owns the keys, and names it "Open Maya Chen". Other columns that point elsewhere use the pill.

NameCurrent companyOwner
Maya ChenNorthwind LabsJoseph Ariel
Priya ShahHalcyon BankSara Lund
import { RecordChip } from '@/ui/record-chip';

const rows = [
  { name: 'Maya Chen', company: 'Northwind Labs', owner: 'Joseph Ariel' },
  { name: 'Priya Shah', company: 'Halcyon Bank', owner: 'Sara Lund' },
];

export default function RecordChipPlain() {
  return (
    <table className="w-full max-w-180 border-collapse text-start text-body leading-body">
      <thead>
        <tr className="h-8 border-b border-border text-body-small leading-body-small font-medium text-text-subtle">
          <th className="px-150 text-start font-medium">Name</th>
          <th className="px-150 text-start font-medium">Current company</th>
          <th className="px-150 text-start font-medium">Owner</th>
        </tr>
      </thead>
      <tbody>
        {rows.map((row) => (
          <tr key={row.name} className="h-9 border-b border-border hover:bg-background-hovered">
            <td className="px-150">
              <RecordChip variant="plain" cell type="candidate" name={row.name} href={`#${row.name}`} />
            </td>
            <td className="px-150">
              <RecordChip cell type="company" name={row.company} href={`#${row.company}`} />
            </td>
            <td className="px-150">
              <RecordChip type="member" name={row.owner} />
            </td>
          </tr>
        ))}
      </tbody>
    </table>
  );
}

Inline, in Flo's text

Inside Flo's replies and approval rows the chip sits on the hovered fill, 22px tall with a 16px mark, so it fits a 24px line of chat text. onOpen opens the record's peek beside the chat; the chip never acts on the record.

Moved to CV sent and drafted the email to at .

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

export default function RecordChipInline() {
  return (
    <p className="max-w-[25rem] text-chat leading-chat text-text">
      Moved <RecordChip variant="inline" type="candidate" name="Maya Chen" onOpen={() => {}} /> to CV sent and drafted the email to{' '}
      <RecordChip variant="inline" type="contact" name="Sara Lee" onOpen={() => {}} /> at{' '}
      <RecordChip variant="inline" type="company" name="Halcyon Bank" src="/examples/halcyon-bank.svg" onOpen={() => {}} />.
    </p>
  );
}

With neither href nor onOpen the chip is a label: no hover, not focusable. Use it for a member, who has no record page.

Joseph ArielMaya Chen
import { RecordChip } from '@/ui/record-chip';

export default function RecordChipStatic() {
  return (
    <div className="flex flex-wrap items-center gap-100">
      <RecordChip type="member" name="Joseph Ariel" />
      <RecordChip variant="inline" type="candidate" name="Maya Chen" />
    </div>
  );
}

With LinkedIn

linkedin adds its own 24px button after the chip. It opens the profile in a new tab, and its click never opens the row around it.

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

export default function RecordChipLinkedIn() {
  return <RecordChip type="contact" name="Sara Lund" href="#sara-lund" linkedin="https://www.linkedin.com/in/sara-lund" />;
}

Long name

The chip takes the room it is given. A name that doesn't fit ends in an ellipsis, and the full name shows in a tooltip.

Greenfield Capital Partners Europe
import { RecordChip } from '@/ui/record-chip';

export default function RecordChipTruncated() {
  return (
    <div className="flex w-45">
      <RecordChip type="company" name="Greenfield Capital Partners Europe" />
    </div>
  );
}

Names in any script

Names keep their own characters and accents, a one-letter company shows that letter, and an email used as a name shows the user icon instead of initials.

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

export default function RecordChipExtremes() {
  return (
    <div className="flex max-w-[25rem] flex-wrap items-center gap-100">
      <RecordChip type="candidate" name="Nguyễn Thị Minh Khai" href="#nguyen" />
      <RecordChip type="candidate" name="王小明" href="#wang" />
      <RecordChip type="contact" name="Zoë O'Brien-Smith" href="#zoe" />
      <RecordChip type="company" name="X" href="#x" />
      <RecordChip type="candidate" name="maya.chen@halcyonbank.com" />
    </div>
  );
}

On this page