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 of the chip (can be inherited from ChipGroup)
Whether the chip is in a selected state (shows remove button unless hideRemove is true)
Whether the chip is disabled
Icon displayed before the chip label
Custom prefix content (e.g., ChipPrefix for avatar, token, logo)
Callback fired when the remove button is clicked (only shown when selected is true)
Hide the remove button even when selected
onClick
(event: React.MouseEvent) => void
Callback fired when the chip is clicked
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.
Default size for all chips in the group
Optional label displayed above the chips
Optional description text displayed below the label
Additional CSS classes to apply to the chip container
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>
<Chip selected hideRemove>
Selected (No Remove)
</Chip>