ComponentsMultiSelect
MultiSelect
Let users search for and choose several options.
On this page
Use this component from the local workspace package. Follow the setup guide first. A public npm package and registry are not available yet.
View registry filesImport the component into your page or component file.
import { MultiSelect, MultiSelectItem } from "@dethink/components";Open the list, type to filter, select multiple options, and remove selected chips from the control.
Basic
Static options with label, helper text, and native form name.
Show sourceexamples/multi-select/basic.tsx
"use client";
import { MultiSelect, MultiSelectItem } from "@dethink/components";
export function MultiSelectBasic() {
return (
<div className="mx-auto max-w-sm">
<MultiSelect
description="Search and select every team that should receive updates."
label="Recipient teams"
name="recipientTeams"
placeholder="Choose teams"
>
<MultiSelectItem value="operations">Operations</MultiSelectItem>
<MultiSelectItem value="finance">Finance</MultiSelectItem>
<MultiSelectItem value="revops">RevOps</MultiSelectItem>
<MultiSelectItem value="customer-success">
Customer success
</MultiSelectItem>
</MultiSelect>
</div>
);
}Controlled
Apps can own the selected array and render derived UI next to the field.
Selected audiences: finance
Show sourceexamples/multi-select/controlled.tsx
"use client";
import { useState } from "react";
import {
FieldDescription,
MultiSelect,
MultiSelectItem,
Stack,
} from "@dethink/components";
export function MultiSelectControlled() {
const [value, setValue] = useState(["finance"]);
return (
<div className="mx-auto max-w-sm">
<Stack gap="3">
<MultiSelect
label="Default audiences"
value={value}
onValueChange={setValue}
>
<MultiSelectItem value="operations">Operations</MultiSelectItem>
<MultiSelectItem value="finance">Finance</MultiSelectItem>
<MultiSelectItem value="revops">RevOps</MultiSelectItem>
</MultiSelect>
<FieldDescription>
Selected audiences: {value.join(", ") || "none"}
</FieldDescription>
</Stack>
</div>
);
}Form states
Invalid, required, disabled option, read-only, and disabled control states.
Show sourceexamples/multi-select/states.tsx
"use client";
import { MultiSelect, MultiSelectItem, Stack } from "@dethink/components";
export function MultiSelectStates() {
return (
<div className="mx-auto max-w-sm">
<Stack gap="4">
<MultiSelect
disabledKeys={["finance"]}
errorMessage="Choose at least one active owner."
invalid
label="Active owners"
required
>
<MultiSelectItem value="operations">Operations</MultiSelectItem>
<MultiSelectItem value="finance">Finance</MultiSelectItem>
<MultiSelectItem value="revops">RevOps</MultiSelectItem>
</MultiSelect>
<MultiSelect
readOnly
defaultValue={["operations", "revops"]}
label="Inherited visibility"
>
<MultiSelectItem value="operations">Operations</MultiSelectItem>
<MultiSelectItem value="revops">RevOps</MultiSelectItem>
</MultiSelect>
<MultiSelect disabled defaultValue={["finance"]} label="Locked teams">
<MultiSelectItem value="finance">Finance</MultiSelectItem>
</MultiSelect>
</Stack>
</div>
);
}Theme, RTL, and wrapping
Nested provider tokens, compact density, RTL direction, and narrow chip wrapping.
Show sourceexamples/multi-select/theme-and-wrapping.tsx
"use client";
import {
DethinkProvider,
MultiSelect,
MultiSelectItem,
} from "@dethink/components";
export function MultiSelectThemeAndWrapping() {
return (
<DethinkProvider theme="dark" density="compact" dir="rtl">
<div className="border-border bg-background mx-auto max-w-72 rounded-lg border p-4">
<MultiSelect
defaultValue={["operations", "finance", "revops", "customer-success"]}
label="فرق التقارير"
name="reportTeams"
>
<MultiSelectItem value="operations">Operations</MultiSelectItem>
<MultiSelectItem value="finance">Finance</MultiSelectItem>
<MultiSelectItem value="revops">RevOps</MultiSelectItem>
<MultiSelectItem value="customer-success">
Customer success
</MultiSelectItem>
</MultiSelect>
</div>
</DethinkProvider>
);
}Examples that combine components for common tasks.
Filter bar
Two MultiSelect controls submit repeated query params for teams and statuses in a dense operations filter.
Show sourceexamples/multi-select/recipe-filter-bar.tsx
"use client";
import { Form, MultiSelect, MultiSelectItem, Stack } from "@dethink/components";
const teamItems = [
{ label: "Operations", value: "operations" },
{ label: "Finance", value: "finance" },
{ label: "RevOps", value: "revops" },
{ label: "Customer success", value: "customer-success" },
];
export function MultiSelectRecipeFilterBar() {
return (
<Form action="/invoices" method="get" className="mx-auto max-w-xl">
<div className="border-border bg-muted/20 rounded-lg border p-4">
<Stack gap="4">
<MultiSelect
defaultValue={["finance"]}
description="Each selected value serializes as a repeated teams field."
items={teamItems}
label="Teams"
name="teams"
>
{(item) => (
<MultiSelectItem key={item.value} value={item.value}>
{item.label}
</MultiSelectItem>
)}
</MultiSelect>
<MultiSelect
defaultValue={["open", "review"]}
label="Status"
name="status"
>
<MultiSelectItem value="open">Open</MultiSelectItem>
<MultiSelectItem value="review">Review</MultiSelectItem>
<MultiSelectItem value="paid">Paid</MultiSelectItem>
<MultiSelectItem value="overdue">Overdue</MultiSelectItem>
</MultiSelect>
</Stack>
</div>
</Form>
);
}MultiSelect owns its field anatomy and selected chip rendering.
| Prop | What it does | Default |
|---|---|---|
value / defaultValue / onValueChangestring[] / string[] / (value) => void | Controlled or uncontrolled selected option values. | [] |
inputValue / defaultInputValue / onInputValueChangestring / string / (text) => void | Controlled or uncontrolled text for the searchable input. | "" |
childrenMultiSelectItem nodes | (item) => MultiSelectItem | Static options, or a render function when passing item data. | Not set |
items / selectedItemsIterable<MultiSelectItemData> | Data-driven options and optional selected item data for stable chip labels. | Not set |
disabledKeysIterable<string> | Option values that cannot be selected. | Not set |
label / description / errorMessageReactNode | The field label, help text, and error message. | Not set |
placeholder / searchPlaceholder / emptyMessageReactNode | Copy for the empty control, chip input, and no-results state. | Not set |
controlSize"sm" | "md" | "lg" | Control height and typography scale. | "md" |
required / disabled / readOnly / invalidboolean | Makes the field required, disabled, read-only, or invalid. | false |
namestring | Repeated hidden input name for native form submission. | Not set |
| Prop | What it does | Default |
|---|---|---|
valuestring | Unique option value used for selection and form submission. | Not set |
childrenReactNode | Visible option label. | Not set |
textValuestring | Plain text used when option children are rich nodes. | Not set |
disabledboolean | Disables this option. | false |