PixelChip

Compact label tag for representing tags, filters, or selections, optionally clickable or removable via an inline delete control.

  • Four visual variants (soft, solid, outline, ghost) across the full tone palette
  • Three sizes (sm, md, lg) with consistent padding + typography rhythm
  • Optional leading icon slot and built-in deletable X button with stop-propagation
  • Renders as a <button> when it handles clicks (onClick in React, @click in Vue, <button pxlChip> in Angular) for native keyboard + screen reader semantics
  • Pixel + linear surface variants share identical API and chamfered/pill geometry
Status
stable
Category
data
Since
v1.0.0

API

import { PixelChip } from '@pxlkit/ui-kit';
PropTypeDefaultDescription
label (required)string—Chip label.
valuestring—Selection value consumed by a wrapping PixelChipGroup. Never rendered to the DOM.
tone'green' | 'cyan' | 'gold' | 'red' | 'purple' | 'pink' | 'neutral''cyan'Tone tint. Defaults to 'cyan'.
surface'pixel' | 'linear'—Visual surface override.
variant'soft' | 'solid' | 'outline' | 'ghost''soft'Variant axis shared with PixelBadge.
size'sm' | 'md' | 'lg''md'Size scale. Defaults to 'md'.
iconLeftReact.ReactNode—Optional leading icon.
onRemove() => void—Legacy alias for onDelete.
deletableboolean—When true (or when onDelete is provided), renders an X button on the right.
onDelete() => void—Called when the X button is activated.
onClickReact.MouseEventHandler<HTMLElement>—When provided the root renders as a <button>. With a delete handler too, a button cannot contain a button, so the label and the X become sibling buttons in a <span> frame that draws the chip; the label button takes the ref and the other props, the frame takes className.

Also takes the native attributes and event handlers of its element (HTMLAttributes<HTMLElement>).

ref points to its element (HTMLElement).

Accessibility

WCAG target: 2.1 AA

  • button

Renders as a <button> only when it handles clicks (onClick, @click in Vue, button[pxlChip] or clickable in Angular), so non-interactive chips stay static. The delete X is a <button> with aria-label "Remove <label>" that never fires the chip click; a button cannot contain a button, so on a clickable chip the label and the X are sibling buttons inside a <span> frame. On a clickable deletable chip the frame shows the label button's keyboard focus; the X shows its own.

Keyboard

KeyActionWhen
EnterActivates the chip when onClick is providedchip is focused
SpaceActivates the chip when onClick is providedchip is focused
EnterRemoves the chip via the X buttondelete button is focused

Usage

import { PixelChip } from '@pxlkit/ui-kit';

export function Default() {
  return <PixelChip label="React" />;
}

Examples

Default

import { PixelChip } from '@pxlkit/ui-kit';

export function Default() {
  return <PixelChip label="React" />;
}

Tones

import { PixelChip } from '@pxlkit/ui-kit';

export function Tones() {
  return (
    <div className="flex flex-wrap gap-2">
      <PixelChip label="Neutral" tone="neutral" />
      <PixelChip label="Green" tone="green" />
      <PixelChip label="Cyan" tone="cyan" />
      <PixelChip label="Gold" tone="gold" />
      <PixelChip label="Red" tone="red" />
      <PixelChip label="Purple" tone="purple" />
      <PixelChip label="Pink" tone="pink" />
    </div>
  );
}

Sizes

import { PixelChip } from '@pxlkit/ui-kit';

export function Sizes() {
  return (
    <div className="flex flex-wrap items-center gap-2">
      <PixelChip label="Small" size="sm" />
      <PixelChip label="Medium" size="md" />
      <PixelChip label="Large" size="lg" />
    </div>
  );
}

Variants

import { PixelChip } from '@pxlkit/ui-kit';

export function Variants() {
  return (
    <div className="flex flex-wrap gap-2">
      <PixelChip label="Soft" variant="soft" tone="cyan" />
      <PixelChip label="Solid" variant="solid" tone="cyan" />
      <PixelChip label="Outline" variant="outline" tone="cyan" />
      <PixelChip label="Ghost" variant="ghost" tone="cyan" />
    </div>
  );
}

Surfaces

import { PixelChip } from '@pxlkit/ui-kit';

export function Surfaces() {
  return (
    <div className="flex flex-wrap gap-2">
      <PixelChip label="Pixel" surface="pixel" tone="green" />
      <PixelChip label="Linear" surface="linear" tone="green" />
    </div>
  );
}

With Icon

import { PixelChip } from '@pxlkit/ui-kit';

export function WithIcon() {
  return (
    <PixelChip
      label="TypeScript"
      tone="cyan"
      iconLeft={<span aria-hidden>TS</span>}
    />
  );
}

Clickable

import { PixelChip } from '@pxlkit/ui-kit';

export function Clickable() {
  return (
    <PixelChip
      label="Click me"
      tone="gold"
      onClick={() => {
        /* noop */
      }}
    />
  );
}

Deletable

import { useState } from 'react';
import { PixelChip } from '@pxlkit/ui-kit';

export function Deletable() {
  const [visible, setVisible] = useState(true);
  if (!visible) return null;
  return (
    <PixelChip
      label="Remove me"
      tone="red"
      onDelete={() => setVisible(false)}
    />
  );
}

Clickable + Deletable

import { useState } from 'react';
import { PixelChip } from '@pxlkit/ui-kit';

export function ClickableAndDeletable() {
  const [visible, setVisible] = useState(true);
  if (!visible) return null;
  return (
    <PixelChip
      label="Tag"
      tone="purple"
      onClick={() => {
        /* select */
      }}
      onDelete={() => setVisible(false)}
    />
  );
}

Related