react ~5 KB 0 deps v0.1.0 ↗ GitHub ↗

@mshafiqyajid/react-chip

Headless chip hook and styled component. Four variants, six tones, selectable, dismissible, icon slots, fully accessible.

Playground #

NeutralPrimarySuccessWarningDangerInfoDismissible
Chip label
Props
TSX
import { ChipStyled } from "@mshafiqyajid/react-chip/styled";
import "@mshafiqyajid/react-chip/styles.css";

<ChipStyled />

Install #

npm install @mshafiqyajid/react-chip

Quick start #

import { ChipStyled } from "@mshafiqyajid/react-chip/styled";
import "@mshafiqyajid/react-chip/styles.css";

<ChipStyled tone="primary">Label</ChipStyled>
<ChipStyled tone="success" variant="solid">Active</ChipStyled>
<ChipStyled tone="danger" dismissible onDismiss={() => {}}>Remove me</ChipStyled>

Selectable chips #

const [selected, setSelected] = useState(false);

<ChipStyled
  tone="primary"
  selectable
  selected={selected}
  onSelect={setSelected}
>
  Toggle me
</ChipStyled>

// Uncontrolled with defaultSelected
<ChipStyled tone="primary" selectable defaultSelected>
  Pre-selected
</ChipStyled>

With icons #

<ChipStyled
  tone="primary"
  icon={<StarIcon />}
  iconRight={<ChevronDownIcon />}
>
  Featured
</ChipStyled>

// Avatar takes priority over icon
<ChipStyled tone="neutral" avatar={<img src="/avatar.jpg" alt="" />}>
  Shafiq Yajid
</ChipStyled>

Headless #

import { useChip } from "@mshafiqyajid/react-chip";

function MyChip({ label }: { label: string }) {
  const { chipProps, dismissProps, isSelected, isDismissed } = useChip({
    selectable: true,
    dismissible: true,
    onSelect: (s) => console.log("selected:", s),
    onDismiss: () => console.log("dismissed"),
  });

  if (isDismissed) return null;

  return (
    <span {...chipProps} className="my-chip" data-selected={isSelected || undefined}>
      {label}
      <button {...dismissProps}>×</button>
    </span>
  );
}

API #

PropTypeDefaultDescription
variant"solid" | "subtle" | "outline" | "soft""subtle"Visual style
tone"neutral" | "primary" | "success" | "warning" | "danger" | "info""neutral"Color tone
size"sm" | "md" | "lg""md"Size scale
selectablebooleanfalseEnable selection toggle; adds role="option" and keyboard support
selectedbooleanControlled selected state
defaultSelectedbooleanfalseUncontrolled initial selected state
onSelect(selected: boolean) => voidCalled when selection changes
dismissiblebooleanfalseShow dismiss button with aria-label="Remove"
onDismiss() => voidCalled when chip is dismissed
iconReactNodeLeading icon
iconRightReactNodeTrailing icon
avatarReactNodeLeading avatar element (takes priority over icon)
disabledbooleanfalseDisable all interactions
childrenReactNodeChip label (required)
classNamestringExtra class on the root element
styleCSSPropertiesInline style override

Headless API — useChip #

OptionTypeDefaultDescription
selectablebooleanfalseEnable selection behavior
selectedbooleanControlled selected state
defaultSelectedbooleanfalseInitial uncontrolled selected state
onSelect(selected: boolean) => voidCalled on selection change
dismissiblebooleanfalseEnable dismiss behavior
onDismiss() => voidCalled when dismissed
disabledbooleanfalseDisable all interactions

Returns chipProps, dismissProps, isSelected, isDismissed, select(v?), and dismiss(). Dismissed chips return isDismissed=true — render null in your component to remove them from the DOM.

Edit this page on GitHub