PixelChipGroup

Controlled chip row with single-select (radiogroup) or multi-select (group of checkboxes) — wraps each PixelChip in a semantic toggle button.

  • Selection is bound — value + onChange (React), v-model (Vue), [(value)] or forms (Angular) — or starts from defaultValue; chips stay presentational.
  • Single mode renders role=radiogroup with roving tabindex + arrow / Home / End navigation.
  • Multi mode renders role=checkbox per chip with aria-checked and Space/Enter toggle.
  • Surface-aware: forwards pixel or linear surface to chip wrappers for consistent borders.
  • aria-label / aria-labelledby make the group an accessible landmark.
Status
stable
Category
data
Since
v1.9.0

API

import { PixelChipGroup } from '@pxlkit/ui-kit';
PropTypeDefaultDescription
valuestring[]—Controlled selection.
defaultValuestring[]—Uncontrolled initial selection.
onChange(next: string[]) => void—Called with the new selection, after each change.
multiplebooleanfalseAny number of chips can be selected (checkboxes) instead of one (radios).
surface'pixel' | 'linear'—Surface override; defaults to the nearest provider.
aria-labelstring—Accessible name (required when single-select so SR users hear the group).
aria-labelledbystring—Id of the element that names the group, in place of aria-label.
children (required)React.ReactNode—The chips, each with a value; other content renders as is.

Also takes the native attributes and event handlers of <div> (HTMLAttributes<HTMLDivElement>).

ref points to <div>.

Accessibility

WCAG target: 2.1 AA

  • radiogroup
  • checkbox-group

Each child chip must declare a string value prop. In single (radiogroup) mode an accessible name (aria-label or aria-labelledby) is required so screen readers announce the group; multi mode renders a bare div unless a name is provided. The wrapping button owns role/aria-checked/tabindex; the PixelChip child remains purely visual. Selection and keyboard focus read apart: the linear surface rings a selected chip and sets the focus ring off it; the pixel surface frames a selected chip inside its border and lights up the chip's edge for focus.

Keyboard

KeyActionWhen
TabMoves focus into / out of the group; in single mode only the selected (or first) chip is tab-reachable.—
SpaceToggles the focused chip.—
EnterToggles the focused chip.—
ArrowRightMoves focus to the next chip and selects it.single mode (radiogroup)
ArrowLeftMoves focus to the previous chip and selects it.single mode (radiogroup)
ArrowDownMoves focus to the next chip and selects it.single mode (radiogroup)
ArrowUpMoves focus to the previous chip and selects it.single mode (radiogroup)
HomeFocuses and selects the first chip.single mode (radiogroup)
EndFocuses and selects the last chip.single mode (radiogroup)

Usage

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

const Chip = PixelChip as unknown as React.ComponentType<
  React.ComponentProps<typeof PixelChip> & { value: string }
>;

export function Default() {
  const [value, setValue] = useState<string[]>(['react']);
  return (
    <PixelChipGroup value={value} onChange={setValue} aria-label="Frameworks">
      <Chip value="react" label="React" tone="cyan" />
      <Chip value="vue" label="Vue" tone="green" />
      <Chip value="svelte" label="Svelte" tone="gold" />
    </PixelChipGroup>
  );
}

Examples

Default

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

const Chip = PixelChip as unknown as React.ComponentType<
  React.ComponentProps<typeof PixelChip> & { value: string }
>;

export function Default() {
  const [value, setValue] = useState<string[]>(['react']);
  return (
    <PixelChipGroup value={value} onChange={setValue} aria-label="Frameworks">
      <Chip value="react" label="React" tone="cyan" />
      <Chip value="vue" label="Vue" tone="green" />
      <Chip value="svelte" label="Svelte" tone="gold" />
    </PixelChipGroup>
  );
}

Multi Select

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

const Chip = PixelChip as unknown as React.ComponentType<
  React.ComponentProps<typeof PixelChip> & { value: string }
>;

export function MultiSelect() {
  const [value, setValue] = useState<string[]>(['ts', 'rust']);
  return (
    <PixelChipGroup
      value={value}
      onChange={setValue}
      multiple
      aria-label="Languages"
    >
      <Chip value="ts" label="TypeScript" tone="cyan" />
      <Chip value="rust" label="Rust" tone="gold" />
      <Chip value="go" label="Go" tone="green" />
      <Chip value="py" label="Python" tone="purple" />
    </PixelChipGroup>
  );
}

Surfaces

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

const Chip = PixelChip as unknown as React.ComponentType<
  React.ComponentProps<typeof PixelChip> & { value: string }
>;

export function Surfaces() {
  const [a, setA] = useState<string[]>(['one']);
  const [b, setB] = useState<string[]>(['one']);
  return (
    <div className="flex flex-col gap-3">
      <PixelChipGroup value={a} onChange={setA} surface="pixel" aria-label="Pixel surface">
        <Chip value="one" label="One" tone="green" />
        <Chip value="two" label="Two" tone="green" />
      </PixelChipGroup>
      <PixelChipGroup value={b} onChange={setB} surface="linear" aria-label="Linear surface">
        <Chip value="one" label="One" tone="cyan" />
        <Chip value="two" label="Two" tone="cyan" />
      </PixelChipGroup>
    </div>
  );
}

Related