Skip to main content

Chip

Compact elements for tags, filters, or selections with optional removal functionality.

Import

import { Chip, ChipGroup } from "@soft-ui/react/chip"

Anatomy

<ChipGroup size="s" label="Tags">
  <Chip selected onRemove={() => {}}>Tag 1</Chip>
  <Chip>Tag 2</Chip>
  <Chip leadingIcon={<Icon />}>Tag 3</Chip>
</ChipGroup>

Chip

Individual chip component for tags and selections.
size
's' | 'm'
default:"'s'"
Size of the chip (can be inherited from ChipGroup)
selected
boolean
default:"false"
Whether the chip is in a selected state (shows remove button unless hideRemove is true)
disabled
boolean
default:"false"
Whether the chip is disabled
leadingIcon
React.ReactNode
Icon displayed before the chip label
prefix
React.ReactNode
Custom prefix content (e.g., ChipPrefix for avatar, token, logo)
onRemove
() => void
Callback fired when the remove button is clicked (only shown when selected is true)
hideRemove
boolean
default:"false"
Hide the remove button even when selected
onClick
(event: React.MouseEvent) => void
Callback fired when the chip is clicked
unsafeClassName
string
Explicit escape hatch for intentional structural overrides

Data Attributes

  • data-slot="chip"
  • data-size: Current size (s, m)
  • data-selected: Present when the chip is selected
  • data-disabled: Present when the chip is disabled

Keyboard Interactions

  • Enter / Space - Activates the chip (triggers onClick)
  • Backspace / Delete - Removes the chip (when selected and onRemove is provided)

ChipGroup

Container for organizing multiple chips with optional label and description.
size
's' | 'm'
default:"'s'"
Default size for all chips in the group
label
string
Optional label displayed above the chips
description
string
Optional description text displayed below the label
className
string
Additional CSS classes to apply to the chip container
unsafeClassName
string
Explicit escape hatch for intentional structural overrides

Data Attributes

  • data-slot="chip-group"
  • data-size: Current size (s, m)

Examples

Basic Chips

<div className="flex gap-2">
  <Chip>Design</Chip>
  <Chip>Development</Chip>
  <Chip>Marketing</Chip>
</div>

Selected Chips with Remove

const [tags, setTags] = React.useState(["React", "TypeScript", "Next.js"])

return (
  <div className="flex gap-2">
    {tags.map((tag) => (
      <Chip
        key={tag}
        selected
        onRemove={() => setTags(tags.filter((t) => t !== tag))}
      >
        {tag}
      </Chip>
    ))}
  </div>
)

With Icons

import { RiStarLine, RiHeartLine, RiBookmarkLine } from "@soft-ui/icons"

<div className="flex gap-2">
  <Chip leadingIcon={<RiStarLine />}>Favorites</Chip>
  <Chip leadingIcon={<RiHeartLine />}>Liked</Chip>
  <Chip leadingIcon={<RiBookmarkLine />}>Saved</Chip>
</div>

Chip Group with Label

<ChipGroup
  label="Categories"
  description="Select categories that interest you"
  size="m"
>
  <Chip>Technology</Chip>
  <Chip selected onRemove={() => {}}>
    Design
  </Chip>
  <Chip>Business</Chip>
  <Chip>Science</Chip>
</ChipGroup>

Different Sizes

<div className="flex flex-col gap-4">
  <div className="flex gap-2">
    <Chip size="s">Small</Chip>
    <Chip size="s" selected onRemove={() => {}}>
      Small Selected
    </Chip>
  </div>
  <div className="flex gap-2">
    <Chip size="m">Medium</Chip>
    <Chip size="m" selected onRemove={() => {}}>
      Medium Selected
    </Chip>
  </div>
</div>

With Custom Prefix

import { ChipPrefix } from "@soft-ui/react/chip-prefix"

<div className="flex gap-2">
  <Chip prefix={<ChipPrefix color="blue">AB</ChipPrefix>}>Alice Brown</Chip>
  <Chip prefix={<ChipPrefix color="green" src="/avatar.jpg" />}>
    John Doe
  </Chip>
</div>

Controlled Selection

const [selected, setSelected] = React.useState(["react"])

const toggleTag = (tag: string) => {
  setSelected((prev) =>
    prev.includes(tag) ? prev.filter((t) => t !== tag) : [...prev, tag]
  )
}

const tags = ["react", "vue", "angular", "svelte"]

return (
  <ChipGroup label="Frameworks">
    {tags.map((tag) => (
      <Chip
        key={tag}
        selected={selected.includes(tag)}
        onClick={() => toggleTag(tag)}
        onRemove={() => toggleTag(tag)}
      >
        {tag}
      </Chip>
    ))}
  </ChipGroup>
)

Disabled State

<div className="flex gap-2">
  <Chip disabled>Disabled</Chip>
  <Chip disabled selected onRemove={() => {}}>
    Disabled Selected
  </Chip>
</div>

Hide Remove Button

<Chip selected hideRemove>
  Selected (No Remove)
</Chip>

Build docs developers (and LLMs) love