Chip
Chip Examples
Copy-ready examples with live previews.
Basic usage
Simple label/tag. Combine variant + style + size for the look you need.
Live preview
Basic
import Chip from "@/_components/chip/Chip";
export default function Example() {
return <Chip label="Design system" variant="primary" style="filled" size="medium" />;
}Variants
Variant controls the color tone (primary/secondary/tertiary/etc).
Live preview
All variants
import Chip from "@/packages/ui/src/_components/chip/Chip";
const variants = ["primary","secondary","tertiary","success","warning","danger","info"] as const;
export default function Example() {
return (
<div style={{ display: "flex", flexWrap: "wrap", gap: 12 }}>
{variants.map((v) => (
<Chip key={v} label={v} variant={v} style="filled" size="medium" />
))}
</div>
);
}Styles
Style controls the surface: "filled", "outlined", or "elevated".
Live preview
filled / outlined / elevated
import Chip from "@/packages/ui/src/_components/chip/Chip";
export default function Example() {
return (
<div style={{ display: "grid", gap: 12 }}>
<div style={{ display: "flex", flexWrap: "wrap", gap: 12 }}>
<Chip label="Primary" variant="primary" style="filled" />
<Chip label="Secondary" variant="secondary" style="filled" />
<Chip label="Tertiary" variant="tertiary" style="filled" />
</div>
<div style={{ display: "flex", flexWrap: "wrap", gap: 12 }}>
<Chip label="Primary" variant="primary" style="outlined" />
<Chip label="Secondary" variant="secondary" style="outlined" />
<Chip label="Tertiary" variant="tertiary" style="outlined" />
</div>
<div style={{ display: "flex", flexWrap: "wrap", gap: 12 }}>
<Chip label="Primary" variant="primary" style="elevated" />
<Chip label="Secondary" variant="secondary" style="elevated" />
<Chip label="Tertiary" variant="tertiary" style="elevated" />
</div>
</div>
);
}Sizes
Size controls the paddings/typography scale.
Live preview
small / medium / large
import Chip from "@/packages/ui/src/_components/chip/Chip";
export default function Example() {
return (
<div style={{ display: "flex", flexWrap: "wrap", gap: 12 }}>
<Chip label="small" variant="secondary" style="outlined" size="small" />
<Chip label="medium" variant="secondary" style="outlined" size="medium" />
<Chip label="large" variant="secondary" style="outlined" size="large" />
</div>
);
}Rounded presets
roundedSize applies a radius preset.
Live preview
roundedSize
import Chip from "@/packages/ui/src/_components/chip/Chip";
export default function Example() {
return (
<div style={{ display: "flex", flexWrap: "wrap", gap: 12 }}>
<Chip label="Rounded sm" variant="primary" style="filled" roundedSize="small" />
<Chip label="Rounded md" variant="primary" style="filled" roundedSize="medium" />
<Chip label="Rounded lg" variant="primary" style="filled" roundedSize="large" />
</div>
);
}Icons
Optional leading icon (iconName) and optional close affordance (iconClose).
• iconClose is currently a visual affordance only (no click handler wired by the component).
• Current implementation always renders the close icon with name="close" and ignores the provided iconClose value.
Live preview
Leading icon
import Chip from "@/packages/ui/src/_components/chip/Chip";
export default function Example() {
return (
<div style={{ display: "flex", flexWrap: "wrap", gap: 12 }}>
<Chip label="Filters" variant="secondary" style="outlined" iconName="Tune" />
<Chip label="Starred" variant="warning" style="filled" iconName="Star" />
<Chip label="Verified" variant="success" style="elevated" iconName="Check" />
</div>
);
}Live preview
Close affordance (visual only)
import Chip from "@/packages/ui/src/_components/chip/Chip";
export default function Example() {
return (
<div style={{ display: "flex", flexWrap: "wrap", gap: 12 }}>
<Chip label="Closable (visual)" variant="secondary" style="outlined" iconClose="true" />
<Chip label="With icon + close" variant="primary" style="filled" iconName="Label" iconClose="true" />
<Chip label="Danger + close" variant="danger" style="filled" iconClose="1" />
</div>
);
}Icons (extended set)
Bigger set of icon chips across styles to validate spacing/alignment.
Live preview
Icon chips grid
import { useMemo } from "react";
import Chip from "@/_components/chip/Chip";
type Row = {
title: string;
style: "filled" | "outlined" | "elevated";
items: Array<{ id: string; label: string; iconName: string; variant: "primary" | "secondary" | "tertiary" | "success" | "warning" | "danger" | "info" }>;
};
export default function Example() {
const rows = useMemo<Row[]>(
() => [
{
title: "Filled",
style: "filled",
items: [
{ id: "wifi", label: "Wi-Fi", iconName: "wifi", variant: "primary" },
{ id: "bluetooth", label: "Bluetooth", iconName: "bluetooth", variant: "secondary" },
{ id: "airplane", label: "Airplane", iconName: "flight", variant: "info" },
{ id: "warning", label: "Warnings", iconName: "warning", variant: "warning" },
{ id: "danger", label: "Errors", iconName: "report", variant: "danger" },
{ id: "success", label: "Done", iconName: "task_alt", variant: "success" },
],
},
{
title: "Outlined",
style: "outlined",
items: [
{ id: "search", label: "Search", iconName: "search", variant: "secondary" },
{ id: "filter", label: "Filter", iconName: "tune", variant: "tertiary" },
{ id: "bookmark", label: "Saved", iconName: "bookmark", variant: "primary" },
{ id: "info", label: "Info", iconName: "info", variant: "info" },
{ id: "bell", label: "Alerts", iconName: "notifications", variant: "warning" },
{ id: "bug", label: "Bugs", iconName: "bug_report", variant: "danger" },
],
},
{
title: "Elevated",
style: "elevated",
items: [
{ id: "user", label: "Profile", iconName: "person", variant: "primary" },
{ id: "settings", label: "Settings", iconName: "settings", variant: "secondary" },
{ id: "image", label: "Photos", iconName: "image", variant: "tertiary" },
{ id: "lock", label: "Security", iconName: "lock", variant: "info" },
{ id: "star", label: "Featured", iconName: "star", variant: "warning" },
{ id: "check", label: "Verified", iconName: "check_circle", variant: "success" },
],
},
],
[]
);
return (
<div style={{ display: "grid", gap: 12 }}>
{rows.map((row) => (
<div key={row.title} style={{ display: "grid", gap: 10, padding: 14, border: "1px solid rgba(0,0,0,0.12)", borderRadius: 12 }}>
<div style={{ fontWeight: 700 }}>{row.title}</div>
<div style={{ display: "flex", flexWrap: "wrap", gap: 12, alignItems: "center" }}>
{row.items.map((it) => (
<Chip key={it.id} label={it.label} iconName={it.iconName} variant={it.variant} style={row.style} size="medium" />
))}
</div>
</div>
))}
</div>
);
}States
Visual states (selected/dragged/disabled).
Live preview
State combinations
import Chip from "@/packages/ui/src/_components/chip/Chip";
export default function Example() {
return (
<div style={{ display: "grid", gap: 12 }}>
<div style={{ display: "flex", flexWrap: "wrap", gap: 12 }}>
<Chip label="Default" variant="primary" style="filled" />
<Chip label="Selected" variant="primary" style="filled" selected />
<Chip label="Dragged" variant="primary" style="filled" dragged />
<Chip label="Disabled" variant="primary" style="filled" disabled />
</div>
<div style={{ display: "flex", flexWrap: "wrap", gap: 12 }}>
<Chip label="Selected + outlined" variant="secondary" style="outlined" selected />
<Chip label="Dragged + outlined" variant="secondary" style="outlined" dragged />
<Chip label="Disabled + outlined" variant="secondary" style="outlined" disabled />
</div>
<div style={{ display: "flex", flexWrap: "wrap", gap: 12 }}>
<Chip label="Selected + elevated" variant="tertiary" style="elevated" selected />
<Chip label="Dragged + elevated" variant="tertiary" style="elevated" dragged />
<Chip label="Disabled + elevated" variant="tertiary" style="elevated" disabled />
</div>
</div>
);
}Controlled selection (wrapper pattern)
Chip is currently presentational (doesn't forward onClick/onChange). This is a minimal workaround to toggle selected state.
• This wrapper pattern is only for demos/playgrounds. Prefer adding native onClick/disabled support inside Chip when you need real interaction.
• Because Chip renders a <button> without type="button", avoid placing it inside a form unless you control submit behavior.
Live preview
Wrapper click toggles selected
import { useMemo, useState } from "react";
import Chip from "@/packages/ui/src/_components/chip/Chip";
type Item = { id: string; label: string };
export default function Example() {
const [selected, setSelected] = useState<string[]>(["design", "ux"]);
const items = useMemo<Item[]>(
() => [
{ id: "design", label: "Design" },
{ id: "ux", label: "UX" },
{ id: "frontend", label: "Frontend" },
{ id: "backend", label: "Backend" },
{ id: "research", label: "Research" },
{ id: "testing", label: "Testing" },
],
[]
);
const toggle = (id: string) =>
setSelected((prev) => (prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id]));
return (
<div style={{ display: "grid", gap: 12 }}>
<div>Selected: {selected.length ? selected.join(", ") : "(none)"}</div>
<div style={{ display: "flex", flexWrap: "wrap", gap: 12 }}>
{items.map((it) => (
<div
key={it.id}
style={{ display: "inline-flex" }}
onClick={(e) => {
e.preventDefault();
toggle(it.id);
}}
>
<Chip label={it.label} variant="secondary" style="outlined" selected={selected.includes(it.id)} />
</div>
))}
</div>
</div>
);
}Stress test (many chips)
Useful to validate wrapping, spacing, and line breaks.
Live preview
Many chips
import { useMemo } from "react";
import Chip from "@/packages/ui/src/_components/chip/Chip";
const variants = ["primary","secondary","tertiary","success","warning","danger","info"] as const;
export default function Example() {
const tags = useMemo(
() => Array.from({ length: 20 }).map((_, i) => ({
id: `t_${i + 1}`,
label: `Tag ${i + 1}`,
variant: variants[i % variants.length],
})),
[]
);
return (
<div style={{ display: "flex", flexWrap: "wrap", gap: 12 }}>
{tags.map((t) => (
<Chip key={t.id} label={t.label} variant={t.variant} style="filled" size="small" />
))}
</div>
);
}Inside a form
Chip renders a <button> without type='button'. Prevent accidental submits in demos.
Live preview
Prevent submit
import { useState } from "react";
import Chip from "@/packages/ui/src/_components/chip/Chip";
import { Button } from "@/packages/ui/src/_components/buttons_variants/buttons/Button";
export default function Example() {
const [submitted, setSubmitted] = useState(false);
return (
<div style={{ display: "grid", gap: 12 }}>
<div>Submitted: {submitted ? "yes" : "no"}</div>
<form
onSubmit={(e) => {
e.preventDefault();
setSubmitted(true);
}}
style={{ display: "grid", gap: 12 }}
>
<div style={{ display: "flex", flexWrap: "wrap", gap: 12 }}>
<Chip label="Inside form" variant="primary" style="filled" />
<Chip label="Outlined" variant="secondary" style="outlined" />
<Chip label="Disabled" variant="secondary" style="outlined" disabled />
</div>
<Button variant="secondary" ripple outline size="small" onClick={() => setSubmitted(false)}>
Reset state
</Button>
</form>
</div>
);
}On this page
Chip Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| label | string | No | — | Text content rendered inside the chip label. |
| variant | "primary" | "secondary" | "tertiary" | "success" | "warning" | "danger" | "info" | No | — | Visual tone (maps to cssnt-chip--*). |
| size | "small" | "medium" | "large" | No | — | Size preset (maps to cssnt-chip--sm/md/lg). |
| style | "outlined" | "filled" | "elevated" | No | — | Surface style preset. |
| roundedSize | "small" | "medium" | "large" | No | — | Border radius preset (maps to cssnt-chip--rounded-*). |
| disabled | boolean | No | false | Adds is-disabled class (visual state). Does not forward the native disabled attribute yet. |
| selected | boolean | No | false | Adds is-selected class (visual state). |
| dragged | boolean | No | false | Adds is-dragged class (visual state). |
| iconName | string | No | — | Optional leading icon name (renders <Icon name={iconName} size='small' />). |
| iconClose | string | No | — | If truthy, shows a trailing close affordance. Current code always renders name='close' and ignores the provided value. |
| onclick | (event: React.MouseEvent<HTMLDivElement>) => void | No | undefined | Declared in the type but not used by the component yet. |
| onchange | (event: React.ChangeEvent<HTMLInputElement>) => void | No | undefined | Declared in the type but not used by the component yet. |
Components