Files
shadcn-ui/apps/v4/registry/bases/base/examples/select-example.tsx
Dominik K. 137b1c12b7 feat(ui): add support for phosphor icons (#9044)
* feat: add phosphor icons to base ui

* feat_ add phosphor to blocks

* feat: add phosphor to radix blocks

* feat: add phosphor to radix ui

* feat: add phosphor to radix example

* feat: add missing phosphor icons

* fix: rename broken icons

* chore: format files

* fix: add missing phosphor icons

* chore: build registry

---------

Co-authored-by: shadcn <m@shadcn.com>
2025-12-17 21:36:46 +04:00

679 lines
18 KiB
TypeScript

"use client"
import {
Example,
ExampleWrapper,
} from "@/registry/bases/base/components/example"
import { Button } from "@/registry/bases/base/ui/button"
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/registry/bases/base/ui/dialog"
import {
Field,
FieldDescription,
FieldError,
FieldLabel,
} from "@/registry/bases/base/ui/field"
import { Input } from "@/registry/bases/base/ui/input"
import {
Item,
ItemContent,
ItemDescription,
ItemTitle,
} from "@/registry/bases/base/ui/item"
import {
NativeSelect,
NativeSelectOption,
} from "@/registry/bases/base/ui/native-select"
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectLabel,
SelectSeparator,
SelectTrigger,
SelectValue,
} from "@/registry/bases/base/ui/select"
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
export default function SelectExample() {
return (
<ExampleWrapper>
<SelectBasic />
<SelectWithIcons />
<SelectWithGroups />
<SelectLargeList />
<SelectMultiple />
<SelectSizes />
<SelectPlan />
<SelectWithButton />
<SelectItemAligned />
<SelectWithField />
<SelectInvalid />
<SelectInline />
<SelectDisabled />
<SelectInDialog />
</ExampleWrapper>
)
}
function SelectBasic() {
const items = [
{ label: "Select a fruit", value: null },
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Blueberry", value: "blueberry" },
{ label: "Grapes", value: "grapes" },
{ label: "Pineapple", value: "pineapple" },
]
return (
<Example title="Basic">
<Select items={items}>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectGroup>
{items.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
</Example>
)
}
function SelectWithIcons() {
const items = [
{
label: (
<>
<IconPlaceholder
lucide="ChartLineIcon"
tabler="IconChartLine"
hugeicons="Chart03Icon"
phosphor="ChartLineIcon"
/>
Chart Type
</>
),
value: null,
},
{
label: (
<>
<IconPlaceholder
lucide="ChartLineIcon"
tabler="IconChartLine"
hugeicons="Chart03Icon"
phosphor="ChartLineIcon"
/>
Line
</>
),
value: "line",
},
{
label: (
<>
<IconPlaceholder
lucide="ChartBarIcon"
tabler="IconChartBar"
hugeicons="Chart03Icon"
phosphor="ChartBarIcon"
/>
Bar
</>
),
value: "bar",
},
{
label: (
<>
<IconPlaceholder
lucide="ChartPieIcon"
tabler="IconChartPie"
hugeicons="Chart03Icon"
phosphor="ChartPieIcon"
/>
Pie
</>
),
value: "pie",
},
]
return (
<Example title="With Icons">
<div className="flex flex-col gap-4">
<Select items={items}>
<SelectTrigger size="sm">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectGroup>
{items.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
<Select items={items}>
<SelectTrigger size="default">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectGroup>
{items.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
</div>
</Example>
)
}
function SelectWithGroups() {
const fruits = [
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Blueberry", value: "blueberry" },
]
const vegetables = [
{ label: "Carrot", value: "carrot" },
{ label: "Broccoli", value: "broccoli" },
{ label: "Spinach", value: "spinach" },
]
const allItems = [
{ label: "Select a fruit", value: null },
...fruits,
...vegetables,
]
return (
<Example title="With Groups & Labels">
<Select items={allItems}>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>Fruits</SelectLabel>
{fruits.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectGroup>
<SelectSeparator />
<SelectGroup>
<SelectLabel>Vegetables</SelectLabel>
{vegetables.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
</Example>
)
}
function SelectLargeList() {
const items = [
{ label: "Select an item", value: null },
...Array.from({ length: 100 }).map((_, i) => ({
label: `Item ${i}`,
value: `item-${i}`,
})),
]
return (
<Example title="Large List">
<Select items={items}>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectGroup>
{items.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
</Example>
)
}
function SelectSizes() {
const items = [
{ label: "Select a fruit", value: null },
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Blueberry", value: "blueberry" },
]
return (
<Example title="Sizes">
<div className="flex flex-col gap-4">
<Select items={items}>
<SelectTrigger size="sm">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectGroup>
{items.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
<Select items={items}>
<SelectTrigger size="default">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectGroup>
{items.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
</div>
</Example>
)
}
function SelectWithButton() {
const items = [
{ label: "Select a fruit", value: null },
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Blueberry", value: "blueberry" },
]
return (
<Example title="With Button">
<div className="flex flex-col gap-4">
<div className="flex items-center gap-2">
<Select items={items}>
<SelectTrigger size="sm">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectGroup>
{items.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
<Button variant="outline" size="sm">
Submit
</Button>
</div>
<div className="flex items-center gap-2">
<Select items={items}>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectGroup>
{items.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
<Button variant="outline">Submit</Button>
</div>
</div>
</Example>
)
}
function SelectItemAligned() {
const items = [
{ label: "Select a fruit", value: null },
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Blueberry", value: "blueberry" },
{ label: "Grapes", value: "grapes", disabled: true },
{ label: "Pineapple", value: "pineapple" },
]
return (
<Example title="Item Aligned">
<Select items={items}>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent alignItemWithTrigger={true}>
<SelectGroup>
{items.map((item) => (
<SelectItem
key={item.value}
value={item.value}
disabled={item.disabled}
>
{item.label}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
</Example>
)
}
function SelectWithField() {
const items = [
{ label: "Select a fruit", value: null },
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Blueberry", value: "blueberry" },
{ label: "Grapes", value: "grapes" },
{ label: "Pineapple", value: "pineapple" },
]
return (
<Example title="With Field">
<Field>
<FieldLabel htmlFor="select-fruit">Favorite Fruit</FieldLabel>
<Select items={items}>
<SelectTrigger id="select-fruit">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectGroup>
{items.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
<FieldDescription>
Choose your favorite fruit from the list.
</FieldDescription>
</Field>
</Example>
)
}
function SelectInvalid() {
const items = [
{ label: "Select a fruit", value: null },
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Blueberry", value: "blueberry" },
{ label: "Grapes", value: "grapes" },
{ label: "Pineapple", value: "pineapple" },
]
return (
<Example title="Invalid">
<div className="flex flex-col gap-4">
<Select items={items}>
<SelectTrigger aria-invalid="true">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectGroup>
{items.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
<Field data-invalid>
<FieldLabel htmlFor="select-fruit-invalid">Favorite Fruit</FieldLabel>
<Select items={items}>
<SelectTrigger id="select-fruit-invalid" aria-invalid>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectGroup>
{items.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
<FieldError errors={[{ message: "Please select a valid fruit." }]} />
</Field>
</div>
</Example>
)
}
function SelectInline() {
const items = [
{ label: "Filter", value: null },
{ label: "All", value: "all" },
{ label: "Active", value: "active" },
{ label: "Inactive", value: "inactive" },
]
return (
<Example title="Inline with Input & NativeSelect">
<div className="flex items-center gap-2">
<Input placeholder="Search..." className="flex-1" />
<Select items={items}>
<SelectTrigger className="w-[140px]">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectGroup>
{items.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
<NativeSelect className="w-[140px]">
<NativeSelectOption value="">Sort by</NativeSelectOption>
<NativeSelectOption value="name">Name</NativeSelectOption>
<NativeSelectOption value="date">Date</NativeSelectOption>
<NativeSelectOption value="status">Status</NativeSelectOption>
</NativeSelect>
</div>
</Example>
)
}
function SelectDisabled() {
const items = [
{ label: "Select a fruit", value: null },
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Blueberry", value: "blueberry" },
{ label: "Grapes", value: "grapes", disabled: true },
{ label: "Pineapple", value: "pineapple" },
]
return (
<Example title="Disabled">
<Select items={items} disabled>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectGroup>
{items.map((item) => (
<SelectItem
key={item.value}
value={item.value}
disabled={item.disabled}
>
{item.label}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
</Example>
)
}
const plans = [
{
name: "Starter",
description: "Perfect for individuals getting started.",
},
{
name: "Professional",
description: "Ideal for growing teams and businesses.",
},
{
name: "Enterprise",
description: "Advanced features for large organizations.",
},
]
function SelectPlan() {
return (
<Example title="Subscription Plan">
<Select
defaultValue={plans[0]}
itemToStringValue={(plan: (typeof plans)[number]) => plan.name}
>
<SelectTrigger className="h-auto! w-72">
<SelectValue>
{(value: (typeof plans)[number]) => <SelectPlanItem plan={value} />}
</SelectValue>
</SelectTrigger>
<SelectContent>
<SelectGroup>
{plans.map((plan) => (
<SelectItem key={plan.name} value={plan}>
<SelectPlanItem plan={plan} />
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
</Example>
)
}
function SelectPlanItem({ plan }: { plan: (typeof plans)[number] }) {
return (
<Item size="xs" className="w-full p-0">
<ItemContent className="gap-0">
<ItemTitle>{plan.name}</ItemTitle>
<ItemDescription className="text-xs">
{plan.description}
</ItemDescription>
</ItemContent>
</Item>
)
}
function SelectMultiple() {
const items = [
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Blueberry", value: "blueberry" },
{ label: "Grapes", value: "grapes" },
{ label: "Pineapple", value: "pineapple" },
{ label: "Strawberry", value: "strawberry" },
{ label: "Watermelon", value: "watermelon" },
]
return (
<Example title="Multiple Selection">
<Select items={items} multiple defaultValue={[]}>
<SelectTrigger className="w-72">
<SelectValue>
{(value: string[]) => {
if (value.length === 0) {
return "Select fruits"
}
if (value.length === 1) {
return items.find((item) => item.value === value[0])?.label
}
return `${value.length} fruits selected`
}}
</SelectValue>
</SelectTrigger>
<SelectContent>
<SelectGroup>
{items.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
</Example>
)
}
function SelectInDialog() {
const items = [
{ label: "Select a fruit", value: null },
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Blueberry", value: "blueberry" },
{ label: "Grapes", value: "grapes" },
{ label: "Pineapple", value: "pineapple" },
]
return (
<Example title="In Dialog">
<Dialog>
<DialogTrigger render={<Button variant="outline" />}>
Open Dialog
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Select Example</DialogTitle>
<DialogDescription>
Use the select below to choose a fruit.
</DialogDescription>
</DialogHeader>
<Select items={items}>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectGroup>
{items.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
</DialogContent>
</Dialog>
</Example>
)
}