Overview
Forms & inputs
Search for a command to run or a page to navigate to.
Multi Select is a form control that allows users to select multiple options from a list of choices.
"use client"
import { useState } from "react"
import {
MultiSelect,
MultiSelectContent,
MultiSelectItem,
MultiSelectTrigger,
} from "@strongtie/design-system/multi-select"
const frameworks = [
{ value: "react", label: "React" },
{ value: "vue", label: "Vue" },
{ value: "angular", label: "Angular" },
{ value: "svelte", label: "Svelte" },
{ value: "nextjs", label: "Next.js" },
{ value: "nuxt", label: "Nuxt" },
{ value: "remix", label: "Remix" },
{ value: "astro", label: "Astro" },
]
export function MultiSelectDefault() {
const [value, setValue] = useState<string[]>([])
return (
<div className="w-[300px]">
<MultiSelect value={value} onValueChange={setValue} items={frameworks}>
<MultiSelectTrigger placeholder="Select frameworks..." />
<MultiSelectContent>
{frameworks.map((framework) => (
<MultiSelectItem
key={framework.value}
value={framework.value}
label={framework.label}
/>
))}
</MultiSelectContent>
</MultiSelect>
</div>
)
}
import { MultiSelect } from "@strongtie/design-system/multi-select"Not installed yet? Add the package to your app:
npm install @strongtie/design-system
This module exports the following components:
MultiSelectRootMultiSelectTriggerMultiSelectContentMultiSelectItemMultiSelectSeparatorMultiSelectGroupMultiSelectLabelMultiSelectClearButtonuseMultiSelect<MultiSelectRoot>| Prop | Type | Default | Description |
|---|---|---|---|
onValueChange * | (value: string[]) => void | - | |
value * | string[] | - | |
disabled | boolean | false | |
items | MultiSelectItemType[] | - | |
maxItems | number | - |
<MultiSelectTrigger>| Prop | Type | Default | Description |
|---|---|---|---|
placeholder | string | - |
<MultiSelectItem>| Prop | Type | Default | Description |
|---|---|---|---|
label | string | - |
"use client"
import * as React from "react"
import {
MultiSelect,
MultiSelectContent,
MultiSelectTrigger,
useMultiSelect,
} from "@strongtie/design-system/multi-select"
import { Check, X } from "lucide-react"
import { cn } from "@/lib/utils"
interface CustomOption {
value: string
label: string
description: string
color: string
}
const options: CustomOption[] = [
{
value: "high",
label: "High Priority",
description: "Critical tasks that need immediate attention",
color: "bg-red-500",
},
{
value: "medium",
label: "Medium Priority",
description: "Important tasks to complete soon",
color: "bg-yellow-500",
},
{
value: "low",
label: "Low Priority",
description: "Tasks that can wait",
color: "bg-green-500",
},
{
value: "backlog",
label: "Backlog",
description: "Future considerations",
color: "bg-gray-500",
},
]
// Custom item component using useMultiSelect hook
function CustomPriorityItem({ option }: { option: CustomOption }) {
const { value, onValueChange } = useMultiSelect()
const isSelected = value.includes(option.value)
const handleToggle = () => {
const newValue = isSelected
? value.filter((v) => v !== option.value)
: [...value, option.value]
onValueChange(newValue)
}
return (
<button
onClick={handleToggle}
type="button"
className={cn(
"hover:bg-accent relative flex w-full cursor-pointer items-start gap-3 px-4 py-3 text-left transition-colors",
isSelected && "bg-accent/50"
)}
>
{/* Color indicator */}
<div className={cn("mt-1 size-3 shrink-0 rounded-full", option.color)} />
{/* Content */}
<div className="flex-1 space-y-1">
<div className="flex items-center gap-2">
<span className="text-sm font-medium">{option.label}</span>
</div>
<p className="text-muted-foreground text-xs">{option.description}</p>
</div>
{/* Selection indicator */}
{isSelected && <Check className="text-primary mt-1 size-4 shrink-0" />}
</button>
)
}
// Custom trigger content using useMultiSelect hook
function CustomTriggerContent() {
const { value, onValueChange } = useMultiSelect()
const handleRemove = (valueToRemove: string, e: React.MouseEvent) => {
e.stopPropagation()
onValueChange(value.filter((v) => v !== valueToRemove))
}
if (value.length === 0) {
return <span className="text-muted-foreground">Select priorities...</span>
}
return (
<div className="flex flex-wrap gap-1.5">
{value.map((val) => {
const option = options.find((opt) => opt.value === val)
if (!option) return null
return (
<div
key={val}
className="bg-secondary flex items-center gap-1.5 rounded-md px-2 py-1 text-xs font-medium"
>
<div className={cn("size-2 rounded-full", option.color)} />
<span>{option.label}</span>
<button
onClick={(e) => handleRemove(val, e)}
className="focus:ring-ring rounded-full transition-opacity outline-none hover:opacity-70 focus:ring-1"
aria-label={`Remove ${option.label}`}
type="button"
>
<X className="size-3" />
</button>
</div>
)
})}
</div>
)
}
export function MultiSelectCustom() {
const [value, setValue] = React.useState<string[]>([])
return (
<div className="w-[400px]">
<MultiSelect value={value} onValueChange={setValue} items={options}>
<MultiSelectTrigger className="min-h-12">
<CustomTriggerContent />
</MultiSelectTrigger>
<MultiSelectContent className="w-[400px]">
<div className="p-2">
<div className="mb-2 px-2">
<h4 className="text-foreground text-xs font-semibold">
Task Priorities
</h4>
<p className="text-muted-foreground text-xs">
Select one or more priority levels
</p>
</div>
<div className="space-y-1">
{options.map((option) => (
<CustomPriorityItem key={option.value} option={option} />
))}
</div>
</div>
</MultiSelectContent>
</MultiSelect>
</div>
)
}
"use client"
import * as React from "react"
import {
MultiSelect,
MultiSelectContent,
MultiSelectItem,
MultiSelectTrigger,
} from "@strongtie/design-system/multi-select"
const options = [
{ value: "home", label: "Home" },
{ value: "settings", label: "Settings" },
{ value: "profile", label: "Profile" },
{ value: "notifications", label: "Notifications" },
]
export function MultiSelectWithIcons() {
const [value, setValue] = React.useState<string[]>([])
return (
<div className="w-[300px]">
<MultiSelect value={value} onValueChange={setValue} items={options}>
<MultiSelectTrigger placeholder="Select options..." />
<MultiSelectContent>
{options.map((option) => (
<MultiSelectItem
key={option.value}
value={option.value}
label={option.label}
/>
))}
</MultiSelectContent>
</MultiSelect>
</div>
)
}