Native Select
Free, copy-and-go Native Select components built on the SevenUI Native Select primitive.Read the primitive docs.
Pick the region closest to most of your users.
1–25 of 312
"use client";
import { Label } from "@/components/ui/label";
import {
NativeSelect,
NativeSelectOption,
} from "@/components/ui/native-select";
const regions = [
{ value: "eu-central", label: "Frankfurt (eu-central-1)" },
{ value: "eu-west", label: "Dublin (eu-west-1)" },
{ value: "us-east", label: "N. Virginia (us-east-1)" },
{ value: "ap-northeast", label: "Tokyo (ap-northeast-1)" },
];
const pageSizes = ["10", "25", "50", "100"];
export default function NativeSelect01() {
return (
<div className="flex w-full max-w-sm flex-col gap-8">
<div className="flex flex-col gap-2">
<Label htmlFor="native-select-01-region">Database region</Label>
<NativeSelect
id="native-select-01-region"
className="w-full"
defaultValue="eu-central"
aria-describedby="native-select-01-region-hint"
>
{regions.map((region) => (
<NativeSelectOption key={region.value} value={region.value}>
{region.label}
</NativeSelectOption>
))}
</NativeSelect>
<p
id="native-select-01-region-hint"
className="text-sm text-muted-foreground"
>
Pick the region closest to most of your users.
</p>
</div>
<div className="flex items-center justify-between gap-3 border-t border-border pt-3 text-xs text-muted-foreground">
<div className="flex items-center gap-2">
<Label
htmlFor="native-select-01-rows"
className="text-xs font-normal text-muted-foreground"
>
Rows
</Label>
<NativeSelect id="native-select-01-rows" size="sm" defaultValue="25">
{pageSizes.map((pageSize) => (
<NativeSelectOption key={pageSize} value={pageSize}>
{pageSize}
</NativeSelectOption>
))}
</NativeSelect>
</div>
<span className="tabular-nums">1–25 of 312</span>
</div>
</div>
);
}
npx shadcn@latest add @sevenui/component/native-select-01pnpm dlx shadcn@latest add @sevenui/component/native-select-01yarn dlx shadcn@latest add @sevenui/component/native-select-01bunx --bun shadcn@latest add @sevenui/component/native-select-01Figma ProfessionalCard ending 4412 · Sep 18
$540.00Hardware over $2,500 goes through an asset request instead.
"use client";
import * as React from "react";
import { Label } from "@/components/ui/label";
import {
NativeSelect,
NativeSelectOptGroup,
NativeSelectOption,
} from "@/components/ui/native-select";
type Category = {
value: string;
label: string;
account: string;
approval: string;
disabled?: boolean;
};
const categoryGroups: { label: string; categories: Category[] }[] = [
{
label: "Travel",
categories: [
{
value: "airfare",
label: "Airfare",
account: "6110",
approval: "Manager approval",
},
{
value: "lodging",
label: "Lodging",
account: "6120",
approval: "Manager approval",
},
{
value: "ground",
label: "Ground transport",
account: "6130",
approval: "Auto-approved under $150",
},
],
},
{
label: "Meals",
categories: [
{
value: "client-meals",
label: "Client meals",
account: "6210",
approval: "Attendee list required",
},
{
value: "team-meals",
label: "Team meals",
account: "6220",
approval: "Auto-approved under $40 per person",
},
],
},
{
label: "Software and equipment",
categories: [
{
value: "saas",
label: "Software subscriptions",
account: "6310",
approval: "IT approval",
},
{
value: "hardware",
label: "Hardware under $2,500",
account: "6320",
approval: "Manager approval",
},
{
value: "capital",
label: "Hardware over $2,500",
account: "1510",
approval: "Filed as an asset request",
disabled: true,
},
],
},
];
const categories = categoryGroups.flatMap((group) => group.categories);
export default function NativeSelect02() {
const [value, setValue] = React.useState("");
const selected = categories.find((item) => item.value === value);
return (
<div className="flex w-full max-w-xs flex-col gap-4">
<div className="flex items-center justify-between gap-3 rounded-lg border border-border px-3 py-2.5">
<div className="grid min-w-0 gap-0.5">
<span className="truncate text-sm font-medium">Figma Professional</span>
<span className="text-xs text-muted-foreground">Card ending 4412 · Sep 18</span>
</div>
<span className="shrink-0 text-sm font-medium tabular-nums">$540.00</span>
</div>
<div className="flex flex-col gap-2">
<Label htmlFor="native-select-02-category">Expense category</Label>
<NativeSelect
id="native-select-02-category"
className="w-full"
required
value={value}
onChange={(event) => setValue(event.target.value)}
aria-describedby="native-select-02-summary"
>
<NativeSelectOption value="" disabled>
Choose a category
</NativeSelectOption>
{categoryGroups.map((group) => (
<NativeSelectOptGroup key={group.label} label={group.label}>
{group.categories.map((item) => (
<NativeSelectOption
key={item.value}
value={item.value}
disabled={item.disabled}
>
{item.disabled
? `${item.label} (asset request)`
: item.label}
</NativeSelectOption>
))}
</NativeSelectOptGroup>
))}
</NativeSelect>
<p
id="native-select-02-summary"
className="text-sm text-muted-foreground"
aria-live="polite"
>
{selected ? (
<>
Posts to account{" "}
<span className="font-medium text-foreground tabular-nums">
{selected.account}
</span>{" "}
· {selected.approval}
</>
) : (
"Hardware over $2,500 goes through an asset request instead."
)}
</p>
</div>
</div>
);
}
npx shadcn@latest add @sevenui/component/native-select-02pnpm dlx shadcn@latest add @sevenui/component/native-select-02yarn dlx shadcn@latest add @sevenui/component/native-select-02bunx --bun shadcn@latest add @sevenui/component/native-select-02"use client";
import { ChevronsUpDownIcon, LanguagesIcon } from "lucide-react";
import * as React from "react";
import { cn } from "cn";
import { Label } from "@/components/ui/label";
import {
NativeSelect,
NativeSelectOption,
} from "@/components/ui/native-select";
const languages = [
{ value: "en", label: "English" },
{ value: "de", label: "Deutsch" },
{ value: "es", label: "Español" },
{ value: "ja", label: "日本語" },
];
const statuses = [
{ value: "operational", label: "Operational", dot: "bg-success" },
{ value: "degraded", label: "Degraded performance", dot: "bg-warning" },
{ value: "outage", label: "Major outage", dot: "bg-destructive" },
{ value: "maintenance", label: "Under maintenance", dot: "bg-muted-foreground" },
];
export default function NativeSelect03() {
const [status, setStatus] = React.useState("operational");
const current = statuses.find((item) => item.value === status);
return (
<div className="flex w-full max-w-xs flex-col gap-6">
<div className="flex flex-col gap-2">
<Label htmlFor="native-select-03-language">Interface language</Label>
<div className="relative">
<LanguagesIcon
aria-hidden="true"
className="pointer-events-none absolute top-1/2 left-2.5 z-10 size-4 -translate-y-1/2 text-muted-foreground"
/>
<NativeSelect
id="native-select-03-language"
defaultValue="en"
className="w-full [&>select]:pl-8"
>
{languages.map((language) => (
<NativeSelectOption key={language.value} value={language.value}>
{language.label}
</NativeSelectOption>
))}
</NativeSelect>
</div>
</div>
<div className="flex flex-col gap-2">
<Label htmlFor="native-select-03-status">API status</Label>
<div className="relative">
<span
aria-hidden="true"
className={cn(
"pointer-events-none absolute top-1/2 left-3 z-10 size-2 -translate-y-1/2 rounded-full transition-colors duration-200",
current?.dot,
)}
/>
<NativeSelect
id="native-select-03-status"
value={status}
onChange={(event) => setStatus(event.target.value)}
className="w-full [&>select]:pl-8 [&>svg]:hidden"
>
{statuses.map((item) => (
<NativeSelectOption key={item.value} value={item.value}>
{item.label}
</NativeSelectOption>
))}
</NativeSelect>
<ChevronsUpDownIcon
aria-hidden="true"
className="pointer-events-none absolute top-1/2 right-2.5 size-3.5 -translate-y-1/2 text-muted-foreground"
/>
</div>
</div>
</div>
);
}
npx shadcn@latest add @sevenui/component/native-select-03pnpm dlx shadcn@latest add @sevenui/component/native-select-03yarn dlx shadcn@latest add @sevenui/component/native-select-03bunx --bun shadcn@latest add @sevenui/component/native-select-0348 conversations
"use client";
import { Label } from "@/components/ui/label";
import {
NativeSelect,
NativeSelectOption,
} from "@/components/ui/native-select";
const priorities = ["Urgent", "High", "Medium", "Low"];
const sortOrders = ["Newest first", "Oldest first", "Most replies"];
const teams = ["Billing", "Growth", "Mobile", "Platform"];
const assignees = ["Unassigned", "Maya Chen", "Jonas Weber", "Priya Raman"];
export default function NativeSelect04() {
return (
<div className="flex w-full max-w-sm flex-col gap-6">
<div className="flex flex-col gap-2">
<Label htmlFor="native-select-04-outline">Priority</Label>
<NativeSelect
id="native-select-04-outline"
defaultValue="High"
className="w-full"
>
{priorities.map((priority) => (
<NativeSelectOption key={priority} value={priority}>
{priority}
</NativeSelectOption>
))}
</NativeSelect>
</div>
<div className="flex flex-col gap-2">
<Label htmlFor="native-select-04-filled">Assignee</Label>
<NativeSelect
id="native-select-04-filled"
defaultValue="Maya Chen"
className="w-full [&>select]:border-transparent [&>select]:bg-muted [&>select]:hover:bg-muted/70"
>
{assignees.map((assignee) => (
<NativeSelectOption key={assignee} value={assignee}>
{assignee}
</NativeSelectOption>
))}
</NativeSelect>
</div>
<div className="flex flex-col gap-2">
<Label htmlFor="native-select-04-underline">Team</Label>
<NativeSelect
id="native-select-04-underline"
defaultValue="Platform"
className="w-full [&>select]:rounded-none [&>select]:border-0 [&>select]:border-b [&>select]:bg-transparent [&>select]:pl-0 [&>select]:focus-visible:shadow-[0_1px_0_var(--color-ring)] [&>select]:focus-visible:ring-0 [&>svg]:right-0"
>
{teams.map((team) => (
<NativeSelectOption key={team} value={team}>
{team}
</NativeSelectOption>
))}
</NativeSelect>
</div>
<div className="flex flex-wrap items-center justify-between gap-x-3 gap-y-1 rounded-lg border border-border bg-card px-3 py-2">
<span className="text-sm font-medium">48 conversations</span>
<div className="flex shrink-0 items-center gap-1 text-sm text-muted-foreground">
<Label
htmlFor="native-select-04-ghost"
className="font-normal text-muted-foreground"
>
Sort
</Label>
<NativeSelect
id="native-select-04-ghost"
size="sm"
defaultValue="Newest first"
className="[&>select]:border-transparent [&>select]:bg-transparent [&>select]:font-medium [&>select]:text-foreground [&>select]:hover:bg-accent"
>
{sortOrders.map((order) => (
<NativeSelectOption key={order} value={order}>
{order}
</NativeSelectOption>
))}
</NativeSelect>
</div>
</div>
</div>
);
}
npx shadcn@latest add @sevenui/component/native-select-04pnpm dlx shadcn@latest add @sevenui/component/native-select-04yarn dlx shadcn@latest add @sevenui/component/native-select-04bunx --bun shadcn@latest add @sevenui/component/native-select-04"use client";
import { CircleAlertIcon, CircleCheckIcon } from "lucide-react";
import * as React from "react";
import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label";
import {
NativeSelect,
NativeSelectOption,
} from "@/components/ui/native-select";
const areas = [
{ value: "billing", label: "Billing and invoices", team: "Payments" },
{ value: "auth", label: "Sign-in and SSO", team: "Identity" },
{ value: "api", label: "API and webhooks", team: "Platform" },
{ value: "editor", label: "Document editor", team: "Editor" },
];
const severities = [
{ value: "sev1", label: "Sev 1 · Production is down" },
{ value: "sev2", label: "Sev 2 · Major feature broken" },
{ value: "sev3", label: "Sev 3 · Workaround exists" },
{ value: "sev4", label: "Sev 4 · Cosmetic or question" },
];
export default function NativeSelect05() {
const [area, setArea] = React.useState("");
const [severity, setSeverity] = React.useState("");
const [submitted, setSubmitted] = React.useState(false);
const [sent, setSent] = React.useState(false);
const areaInvalid = submitted && !area;
const severityInvalid = submitted && !severity;
const complete = sent;
const team = areas.find((item) => item.value === area)?.team;
function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
event.preventDefault();
setSubmitted(true);
setSent(Boolean(area) && Boolean(severity));
}
return (
<form
noValidate
onSubmit={handleSubmit}
className="flex w-full max-w-xs flex-col gap-5"
>
<div className="flex flex-col gap-2">
<Label htmlFor="native-select-05-area">Product area</Label>
<NativeSelect
id="native-select-05-area"
className="w-full"
value={area}
required
aria-invalid={areaInvalid || undefined}
aria-describedby={
areaInvalid ? "native-select-05-area-error" : undefined
}
onChange={(event) => {
setArea(event.target.value);
setSent(false);
}}
>
<NativeSelectOption value="" disabled>
Where did it happen?
</NativeSelectOption>
{areas.map((item) => (
<NativeSelectOption key={item.value} value={item.value}>
{item.label}
</NativeSelectOption>
))}
</NativeSelect>
{areaInvalid ? (
<p
id="native-select-05-area-error"
className="flex items-center gap-1.5 text-sm text-destructive"
>
<CircleAlertIcon aria-hidden="true" className="size-3.5 shrink-0" />
Pick an area so the right team sees this.
</p>
) : null}
</div>
<div className="flex flex-col gap-2">
<Label htmlFor="native-select-05-severity">Severity</Label>
<NativeSelect
id="native-select-05-severity"
className="w-full"
value={severity}
required
aria-invalid={severityInvalid || undefined}
aria-describedby="native-select-05-severity-hint"
onChange={(event) => {
setSeverity(event.target.value);
setSent(false);
}}
>
<NativeSelectOption value="" disabled>
How bad is it?
</NativeSelectOption>
{severities.map((item) => (
<NativeSelectOption key={item.value} value={item.value}>
{item.label}
</NativeSelectOption>
))}
</NativeSelect>
<p
id="native-select-05-severity-hint"
className={
severityInvalid
? "flex items-center gap-1.5 text-sm text-destructive"
: "text-sm text-muted-foreground"
}
>
{severityInvalid ? (
<>
<CircleAlertIcon
aria-hidden="true"
className="size-3.5 shrink-0"
/>
Choose a severity to set the response time.
</>
) : severity === "sev1" ? (
"Sev 1 pages the on-call engineer immediately."
) : (
"Sev 1 pages on-call; others get a reply within one business day."
)}
</p>
</div>
<div className="flex flex-col gap-3">
<Button type="submit" className="w-full">
Submit report
</Button>
<p
aria-live="polite"
className="flex min-h-5 items-center justify-center gap-1.5 text-sm text-success"
>
{complete ? (
<>
<CircleCheckIcon
aria-hidden="true"
className="size-3.5 shrink-0"
/>
Routed to the {team} team
</>
) : null}
</p>
</div>
</form>
);
}
npx shadcn@latest add @sevenui/component/native-select-05pnpm dlx shadcn@latest add @sevenui/component/native-select-05yarn dlx shadcn@latest add @sevenui/component/native-select-05bunx --bun shadcn@latest add @sevenui/component/native-select-052 selected
Hold Ctrl or Cmd to pick more than one.
#deploys#incidents
"use client";
import { XIcon } from "lucide-react";
import * as React from "react";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label";
import {
NativeSelect,
NativeSelectOptGroup,
NativeSelectOption,
} from "@/components/ui/native-select";
const channelGroups = [
{
label: "Engineering",
channels: ["#deploys", "#incidents", "#code-review"],
},
{
label: "Company",
channels: ["#announcements", "#design-crit", "#random"],
},
];
export default function NativeSelect06() {
const [channels, setChannels] = React.useState<string[]>([
"#deploys",
"#incidents",
]);
function remove(channel: string) {
setChannels((current) => current.filter((item) => item !== channel));
}
return (
<div className="flex w-full max-w-xs flex-col gap-2">
<div className="flex items-baseline justify-between gap-2">
<Label htmlFor="native-select-06-channels">Alert channels</Label>
<span className="text-xs text-muted-foreground tabular-nums">
{channels.length} selected
</span>
</div>
<NativeSelect
id="native-select-06-channels"
multiple
value={channels}
aria-describedby="native-select-06-hint"
onChange={(event) =>
setChannels(
Array.from(event.target.selectedOptions, (option) => option.value),
)
}
className="w-full [&>select]:h-52 [&>select]:overflow-y-auto [&>select]:p-1 [&>svg]:hidden [&_option]:rounded-md [&_option]:px-2 [&_option]:py-1 [&_option:checked]:bg-accent [&_option:checked]:text-accent-foreground"
>
{channelGroups.map((group) => (
<NativeSelectOptGroup key={group.label} label={group.label}>
{group.channels.map((channel) => (
<NativeSelectOption key={channel} value={channel}>
{channel}
</NativeSelectOption>
))}
</NativeSelectOptGroup>
))}
</NativeSelect>
<p id="native-select-06-hint" className="text-xs text-muted-foreground">
Hold Ctrl or Cmd to pick more than one.
</p>
<div className="flex min-h-7 flex-wrap items-center gap-1.5">
{channels.map((channel) => (
<Badge key={channel} variant="secondary" className="gap-1 pr-1">
{channel}
<button
type="button"
onClick={() => remove(channel)}
aria-label={`Remove ${channel}`}
className="rounded-sm text-muted-foreground outline-none hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring"
>
<XIcon aria-hidden="true" className="size-3" />
</button>
</Badge>
))}
{channels.length > 0 ? (
<Button
type="button"
variant="ghost"
size="xs"
onClick={() => setChannels([])}
>
Clear all
</Button>
) : (
<span className="text-xs text-muted-foreground">
No channels will be notified.
</span>
)}
</div>
</div>
);
}
npx shadcn@latest add @sevenui/component/native-select-06pnpm dlx shadcn@latest add @sevenui/component/native-select-06yarn dlx shadcn@latest add @sevenui/component/native-select-06bunx --bun shadcn@latest add @sevenui/component/native-select-063 warehouses offer same-day pickup.
"use client";
import * as React from "react";
import { Label } from "@/components/ui/label";
import {
NativeSelect,
NativeSelectOption,
} from "@/components/ui/native-select";
import { Spinner } from "@/components/ui/spinner";
const countries = [
{ value: "de", label: "Germany" },
{ value: "jp", label: "Japan" },
{ value: "ca", label: "Canada" },
{ value: "is", label: "Iceland" },
];
// Stand-in for a server response; Iceland has no pickup points yet.
const warehousesByCountry: Record<string, string[]> = {
de: ["Berlin Tempelhof", "Hamburg Harbor", "Munich East"],
jp: ["Tokyo Koto", "Osaka Bay"],
ca: ["Toronto Pearson", "Vancouver Richmond", "Montreal Dorval"],
is: [],
};
export default function NativeSelect07() {
const [country, setCountry] = React.useState("de");
const [warehouse, setWarehouse] = React.useState("Berlin Tempelhof");
const [warehouses, setWarehouses] = React.useState<string[]>(
warehousesByCountry.de,
);
const [loading, setLoading] = React.useState(false);
React.useEffect(() => {
if (!loading) return;
const timeout = window.setTimeout(() => {
const next = warehousesByCountry[country] ?? [];
setWarehouses(next);
setWarehouse(next[0] ?? "");
setLoading(false);
}, 700);
return () => window.clearTimeout(timeout);
}, [country, loading]);
const empty = !loading && warehouses.length === 0;
return (
<div className="flex w-full max-w-xs flex-col gap-5">
<div className="flex flex-col gap-2">
<Label htmlFor="native-select-07-country">Country</Label>
<NativeSelect
id="native-select-07-country"
className="w-full"
value={country}
onChange={(event) => {
setCountry(event.target.value);
setLoading(true);
}}
>
{countries.map((item) => (
<NativeSelectOption key={item.value} value={item.value}>
{item.label}
</NativeSelectOption>
))}
</NativeSelect>
</div>
<div className="flex flex-col gap-2">
<Label htmlFor="native-select-07-warehouse">Pickup warehouse</Label>
<div className="relative">
<NativeSelect
id="native-select-07-warehouse"
className={loading ? "w-full [&>svg]:hidden" : "w-full"}
value={loading || empty ? "" : warehouse}
disabled={loading || empty}
aria-busy={loading || undefined}
aria-describedby="native-select-07-status"
onChange={(event) => setWarehouse(event.target.value)}
>
{loading ? (
<NativeSelectOption value="">Loading warehouses…</NativeSelectOption>
) : empty ? (
<NativeSelectOption value="">No warehouses available</NativeSelectOption>
) : (
warehouses.map((item) => (
<NativeSelectOption key={item} value={item}>
{item}
</NativeSelectOption>
))
)}
</NativeSelect>
{loading ? (
<Spinner
aria-hidden="true"
role="presentation"
className="pointer-events-none absolute top-1/2 right-2.5 -translate-y-1/2 text-muted-foreground"
/>
) : null}
</div>
<p
id="native-select-07-status"
aria-live="polite"
className="text-sm text-muted-foreground"
>
{loading
? "Checking which warehouses ship to this country."
: empty
? "Iceland orders ship directly from our Dublin hub."
: `${warehouses.length} warehouses offer same-day pickup.`}
</p>
</div>
</div>
);
}
npx shadcn@latest add @sevenui/component/native-select-07pnpm dlx shadcn@latest add @sevenui/component/native-select-07yarn dlx shadcn@latest add @sevenui/component/native-select-07bunx --bun shadcn@latest add @sevenui/component/native-select-073 tickets selected
"use client";
import { CheckIcon } from "lucide-react";
import * as React from "react";
import { Button } from "@/components/ui/button";
import { ButtonGroup } from "@/components/ui/button-group";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
NativeSelect,
NativeSelectOption,
} from "@/components/ui/native-select";
const dialCodes = [
{ value: "+1", label: "US +1" },
{ value: "+44", label: "UK +44" },
{ value: "+49", label: "DE +49" },
{ value: "+90", label: "TR +90" },
];
const currencies = ["USD", "EUR", "GBP", "JPY"];
const bulkActions = [
{ value: "archive", label: "Archive" },
{ value: "assign", label: "Assign to me" },
{ value: "export", label: "Export as CSV" },
];
const appliedLabels: Record<string, string> = {
archive: "3 tickets archived",
assign: "3 tickets assigned to you",
export: "Export started for 3 tickets",
};
export default function NativeSelect08() {
const [action, setAction] = React.useState("archive");
const [applied, setApplied] = React.useState<string | null>(null);
return (
<div className="flex w-full max-w-sm flex-col gap-6">
<div className="flex flex-col gap-2">
<Label htmlFor="native-select-08-phone">Phone number</Label>
<ButtonGroup className="w-full">
<NativeSelect
defaultValue="+49"
aria-label="Country dialing code"
className="shrink-0 [&>select]:rounded-r-none"
>
{dialCodes.map((code) => (
<NativeSelectOption key={code.value} value={code.value}>
{code.label}
</NativeSelectOption>
))}
</NativeSelect>
<Input
id="native-select-08-phone"
type="tel"
inputMode="tel"
autoComplete="tel-national"
placeholder="151 2345 6789"
/>
</ButtonGroup>
</div>
<div className="flex flex-col gap-2">
<Label htmlFor="native-select-08-amount">Invoice amount</Label>
<ButtonGroup className="w-full">
<Input
id="native-select-08-amount"
inputMode="decimal"
defaultValue="1,250.00"
className="tabular-nums"
/>
<NativeSelect
defaultValue="EUR"
aria-label="Currency"
className="shrink-0 [&>select]:rounded-l-none [&>select]:border-l-0"
>
{currencies.map((currency) => (
<NativeSelectOption key={currency} value={currency}>
{currency}
</NativeSelectOption>
))}
</NativeSelect>
</ButtonGroup>
</div>
<div className="flex flex-wrap items-center justify-between gap-3 rounded-lg border border-border bg-muted/40 p-2 pl-3">
<span
aria-live="polite"
className="flex items-center gap-1.5 text-sm font-medium tabular-nums"
>
{applied ? (
<>
<CheckIcon aria-hidden="true" className="size-3.5 text-success" />
{applied}
</>
) : (
"3 tickets selected"
)}
</span>
<ButtonGroup>
<NativeSelect
size="sm"
value={action}
onChange={(event) => {
setAction(event.target.value);
setApplied(null);
}}
aria-label="Bulk action"
className="[&>select]:rounded-r-none [&>select]:bg-background"
>
{bulkActions.map((action) => (
<NativeSelectOption key={action.value} value={action.value}>
{action.label}
</NativeSelectOption>
))}
</NativeSelect>
<Button
size="sm"
variant="outline"
type="button"
onClick={() => setApplied(appliedLabels[action] ?? null)}
>
Apply
</Button>
</ButtonGroup>
</div>
</div>
);
}
npx shadcn@latest add @sevenui/component/native-select-08pnpm dlx shadcn@latest add @sevenui/component/native-select-08yarn dlx shadcn@latest add @sevenui/component/native-select-08bunx --bun shadcn@latest add @sevenui/component/native-select-08"use client";
import * as React from "react";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
NativeSelect,
NativeSelectOption,
} from "@/components/ui/native-select";
type Country = {
code: string;
name: string;
regionLabel: string;
postalLabel: string;
postalPlaceholder: string;
regions: string[];
};
const countries: Country[] = [
{
code: "US",
name: "United States",
regionLabel: "State",
postalLabel: "ZIP code",
postalPlaceholder: "94103",
regions: ["California", "New York", "Texas", "Washington"],
},
{
code: "CA",
name: "Canada",
regionLabel: "Province",
postalLabel: "Postal code",
postalPlaceholder: "M5V 2T6",
regions: ["Alberta", "British Columbia", "Ontario", "Quebec"],
},
{
code: "GB",
name: "United Kingdom",
regionLabel: "County",
postalLabel: "Postcode",
postalPlaceholder: "SW1A 1AA",
regions: ["Greater London", "Greater Manchester", "Kent", "West Yorkshire"],
},
{
code: "AU",
name: "Australia",
regionLabel: "State or territory",
postalLabel: "Postcode",
postalPlaceholder: "2000",
regions: ["New South Wales", "Queensland", "Victoria", "Western Australia"],
},
];
export default function NativeSelect09() {
const [countryCode, setCountryCode] = React.useState("US");
const [region, setRegion] = React.useState("");
const country =
countries.find((item) => item.code === countryCode) ?? countries[0];
return (
<form
className="grid w-full max-w-sm gap-4"
onSubmit={(event) => event.preventDefault()}
>
<div className="grid gap-1">
<h3 className="text-base font-medium">Shipping address</h3>
<p className="text-sm text-muted-foreground">
Fields adapt to the country you ship to.
</p>
</div>
<div className="grid gap-2">
<Label htmlFor="native-select-09-country">Country</Label>
<NativeSelect
id="native-select-09-country"
className="w-full"
autoComplete="country"
value={countryCode}
onChange={(event) => {
setCountryCode(event.target.value);
setRegion("");
}}
>
{countries.map((item) => (
<NativeSelectOption key={item.code} value={item.code}>
{item.name}
</NativeSelectOption>
))}
</NativeSelect>
</div>
<div className="grid gap-2">
<Label htmlFor="native-select-09-street">Street address</Label>
<Input
id="native-select-09-street"
autoComplete="street-address"
placeholder="500 Market Street, Suite 2"
/>
</div>
<div className="grid gap-4 sm:grid-cols-2">
<div className="grid gap-2">
<Label htmlFor="native-select-09-region">{country.regionLabel}</Label>
<NativeSelect
id="native-select-09-region"
className="w-full"
autoComplete="address-level1"
required
value={region}
onChange={(event) => setRegion(event.target.value)}
>
<NativeSelectOption value="" disabled>
Select {country.regionLabel.toLowerCase()}
</NativeSelectOption>
{country.regions.map((item) => (
<NativeSelectOption key={item} value={item}>
{item}
</NativeSelectOption>
))}
</NativeSelect>
</div>
<div className="grid gap-2">
<Label htmlFor="native-select-09-postal">{country.postalLabel}</Label>
<Input
id="native-select-09-postal"
autoComplete="postal-code"
placeholder={country.postalPlaceholder}
/>
</div>
</div>
</form>
);
}
npx shadcn@latest add @sevenui/component/native-select-09pnpm dlx shadcn@latest add @sevenui/component/native-select-09yarn dlx shadcn@latest add @sevenui/component/native-select-09bunx --bun shadcn@latest add @sevenui/component/native-select-09"use client";
import * as React from "react";
import {
Card,
CardAction,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import {
NativeSelect,
NativeSelectOption,
} from "@/components/ui/native-select";
type Range = "7d" | "30d" | "90d";
type Source = { name: string; visits: number };
const ranges: { value: Range; label: string }[] = [
{ value: "7d", label: "Last 7 days" },
{ value: "30d", label: "Last 30 days" },
{ value: "90d", label: "Last 90 days" },
];
const sourcesByRange: Record<Range, Source[]> = {
"7d": [
{ name: "Google Search", visits: 4820 },
{ name: "Direct", visits: 2310 },
{ name: "GitHub", visits: 1455 },
{ name: "Hacker News", visits: 930 },
{ name: "Newsletter", visits: 412 },
],
"30d": [
{ name: "Google Search", visits: 19240 },
{ name: "Direct", visits: 9875 },
{ name: "Newsletter", visits: 6120 },
{ name: "GitHub", visits: 5480 },
{ name: "Hacker News", visits: 2215 },
],
"90d": [
{ name: "Google Search", visits: 58710 },
{ name: "Direct", visits: 30460 },
{ name: "Hacker News", visits: 21980 },
{ name: "GitHub", visits: 16305 },
{ name: "Newsletter", visits: 14870 },
],
};
const formatter = new Intl.NumberFormat("en-US");
export default function NativeSelect10() {
const [range, setRange] = React.useState<Range>("30d");
const sources = sourcesByRange[range];
const total = sources.reduce((sum, source) => sum + source.visits, 0);
const max = Math.max(...sources.map((source) => source.visits));
return (
<Card className="w-full max-w-sm">
<CardHeader>
<CardTitle>Top referrers</CardTitle>
<CardDescription>
<span className="font-medium text-foreground tabular-nums">
{formatter.format(total)}
</span>{" "}
visits from 5 sources
</CardDescription>
<CardAction>
<NativeSelect
size="sm"
aria-label="Reporting period"
value={range}
onChange={(event) => setRange(event.target.value as Range)}
>
{ranges.map((item) => (
<NativeSelectOption key={item.value} value={item.value}>
{item.label}
</NativeSelectOption>
))}
</NativeSelect>
</CardAction>
</CardHeader>
<CardContent>
<ul className="grid gap-1.5">
{sources.map((source) => (
<li
key={source.name}
className="relative flex items-center justify-between gap-3 overflow-hidden rounded-md px-2.5 py-1.5"
>
<span
aria-hidden="true"
className="absolute inset-y-0 left-0 rounded-md bg-chart-2/15 transition-[width] duration-300 ease-out"
style={{ width: `${(source.visits / max) * 100}%` }}
/>
<span className="relative truncate">{source.name}</span>
<span className="relative shrink-0 text-muted-foreground tabular-nums">
{formatter.format(source.visits)}
</span>
</li>
))}
</ul>
</CardContent>
</Card>
);
}
npx shadcn@latest add @sevenui/component/native-select-10pnpm dlx shadcn@latest add @sevenui/component/native-select-10yarn dlx shadcn@latest add @sevenui/component/native-select-10bunx --bun shadcn@latest add @sevenui/component/native-select-10"use client";
import * as React from "react";
import { Button } from "@/components/ui/button";
import {
NativeSelect,
NativeSelectOption,
} from "@/components/ui/native-select";
import { Separator } from "@/components/ui/separator";
type Frequency = "instant" | "hourly" | "daily" | "off";
const frequencies: { value: Frequency; label: string }[] = [
{ value: "instant", label: "Instantly" },
{ value: "hourly", label: "Hourly digest" },
{ value: "daily", label: "Daily digest" },
{ value: "off", label: "Off" },
];
const topics = [
{
id: "mentions",
title: "Mentions and replies",
description: "When someone @mentions you or replies to your comment.",
},
{
id: "assigned",
title: "Assigned issues",
description: "When an issue is assigned to you or its status changes.",
},
{
id: "deploys",
title: "Failed deployments",
description: "When a production or preview build fails.",
},
{
id: "product",
title: "Product updates",
description: "New features and changelog highlights, about twice a month.",
},
] as const;
type TopicId = (typeof topics)[number]["id"];
const saved: Record<TopicId, Frequency> = {
mentions: "instant",
assigned: "hourly",
deploys: "instant",
product: "off",
};
export default function NativeSelect11() {
const [baseline, setBaseline] = React.useState(saved);
const [values, setValues] = React.useState(saved);
const changed = topics.filter(
(topic) => values[topic.id] !== baseline[topic.id],
).length;
return (
<form
className="w-full max-w-md rounded-xl border bg-card text-card-foreground"
onSubmit={(event) => {
event.preventDefault();
setBaseline(values);
}}
>
<div className="grid gap-1 p-4">
<h3 className="text-base font-medium">Email notifications</h3>
<p className="text-sm text-muted-foreground">
Choose how often each kind of update reaches your inbox.
</p>
</div>
<Separator />
<ul className="divide-y">
{topics.map((topic) => {
const id = `native-select-11-${topic.id}`;
return (
<li
key={topic.id}
className="flex flex-col gap-2 p-4 sm:flex-row sm:items-center sm:justify-between sm:gap-6"
>
<div className="grid gap-0.5">
<label htmlFor={id} className="text-sm font-medium">
{topic.title}
</label>
<p
id={`${id}-description`}
className="text-sm text-muted-foreground"
>
{topic.description}
</p>
</div>
<NativeSelect
id={id}
aria-describedby={`${id}-description`}
className="w-full shrink-0 sm:w-40"
value={values[topic.id]}
onChange={(event) =>
setValues((current) => ({
...current,
[topic.id]: event.target.value as Frequency,
}))
}
>
{frequencies.map((frequency) => (
<NativeSelectOption
key={frequency.value}
value={frequency.value}
>
{frequency.label}
</NativeSelectOption>
))}
</NativeSelect>
</li>
);
})}
</ul>
<Separator />
<div className="flex flex-wrap items-center justify-between gap-3 p-4">
<p className="text-sm text-muted-foreground" aria-live="polite">
{changed === 0
? "All changes saved"
: `${changed} unsaved ${changed === 1 ? "change" : "changes"}`}
</p>
<div className="flex gap-2">
<Button
type="button"
variant="ghost"
disabled={changed === 0}
onClick={() => setValues(baseline)}
>
Discard
</Button>
<Button type="submit" disabled={changed === 0}>
Save preferences
</Button>
</div>
</div>
</form>
);
}
npx shadcn@latest add @sevenui/component/native-select-11pnpm dlx shadcn@latest add @sevenui/component/native-select-11yarn dlx shadcn@latest add @sevenui/component/native-select-11bunx --bun shadcn@latest add @sevenui/component/native-select-11Workspace members
4 people · 2 can manage billing and settings
- OwnerPriya Ramanpriya@northwind.io
- Daniel Okafordaniel@northwind.io
- Sofia Lindqvistsofia@northwind.io
- marcus@contractor.devInvitedInvitation sent 2 days ago
"use client";
import * as React from "react";
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
import { Badge } from "@/components/ui/badge";
import {
NativeSelect,
NativeSelectOption,
} from "@/components/ui/native-select";
type Role = "owner" | "admin" | "member" | "viewer";
type Member = {
id: string;
name: string;
email: string;
initials: string;
role: Role;
pending?: boolean;
};
const roles: { value: Role; label: string }[] = [
{ value: "admin", label: "Admin" },
{ value: "member", label: "Member" },
{ value: "viewer", label: "Viewer" },
];
const initialMembers: Member[] = [
{
id: "m1",
name: "Priya Raman",
email: "priya@northwind.io",
initials: "PR",
role: "owner",
},
{
id: "m2",
name: "Daniel Okafor",
email: "daniel@northwind.io",
initials: "DO",
role: "admin",
},
{
id: "m3",
name: "Sofia Lindqvist",
email: "sofia@northwind.io",
initials: "SL",
role: "member",
},
{
id: "m4",
name: "marcus@contractor.dev",
email: "Invitation sent 2 days ago",
initials: "M",
role: "viewer",
pending: true,
},
];
export default function NativeSelect12() {
const [members, setMembers] = React.useState(initialMembers);
const admins = members.filter(
(member) => member.role === "owner" || member.role === "admin",
).length;
return (
<section
aria-labelledby="native-select-12-title"
className="w-full max-w-md rounded-xl border bg-card text-card-foreground"
>
<div className="grid gap-1 p-4">
<h3 id="native-select-12-title" className="text-base font-medium">
Workspace members
</h3>
<p className="text-sm text-muted-foreground">
{members.length} people · {admins} can manage billing and settings
</p>
</div>
<ul className="divide-y border-t">
{members.map((member) => (
<li key={member.id} className="flex items-center gap-3 px-4 py-3">
<Avatar className="hidden sm:flex">
<AvatarFallback>{member.initials}</AvatarFallback>
</Avatar>
<div className="grid min-w-0 flex-1 gap-0.5">
<div className="flex min-w-0 items-center gap-2">
<span className="truncate text-sm font-medium">
{member.name}
</span>
{member.pending ? (
<Badge variant="outline" className="shrink-0">
Invited
</Badge>
) : null}
</div>
<span className="truncate text-sm text-muted-foreground">
{member.email}
</span>
</div>
{member.role === "owner" ? (
<span className="shrink-0 px-2.5 text-sm text-muted-foreground">
Owner
</span>
) : (
<NativeSelect
size="sm"
className="shrink-0"
aria-label={`Role for ${member.name}`}
value={member.role}
onChange={(event) => {
const role = event.target.value as Role;
setMembers((current) =>
current.map((item) =>
item.id === member.id ? { ...item, role } : item,
),
);
}}
>
{roles.map((role) => (
<NativeSelectOption key={role.value} value={role.value}>
{role.label}
</NativeSelectOption>
))}
</NativeSelect>
)}
</li>
))}
</ul>
</section>
);
}
npx shadcn@latest add @sevenui/component/native-select-12pnpm dlx shadcn@latest add @sevenui/component/native-select-12yarn dlx shadcn@latest add @sevenui/component/native-select-12bunx --bun shadcn@latest add @sevenui/component/native-select-12Product demo with Lena Hart
Thursday, October 2 (UTC)
Pick a time to continue.
"use client";
import { CalendarCheck, Clock, Globe } from "lucide-react";
import * as React from "react";
import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label";
import {
NativeSelect,
NativeSelectOptGroup,
NativeSelectOption,
} from "@/components/ui/native-select";
const timezoneGroups = [
{
label: "Americas",
zones: [
{ id: "america-los-angeles", label: "Los Angeles (UTC−7)", offset: -7 },
{ id: "america-new-york", label: "New York (UTC−4)", offset: -4 },
{ id: "america-sao-paulo", label: "São Paulo (UTC−3)", offset: -3 },
],
},
{
label: "Europe and Africa",
zones: [
{ id: "europe-london", label: "London (UTC+1)", offset: 1 },
{ id: "europe-berlin", label: "Berlin (UTC+2)", offset: 2 },
{ id: "africa-nairobi", label: "Nairobi (UTC+3)", offset: 3 },
],
},
{
label: "Asia Pacific",
zones: [
{ id: "asia-kolkata", label: "Kolkata (UTC+5:30)", offset: 5.5 },
{ id: "asia-tokyo", label: "Tokyo (UTC+9)", offset: 9 },
{ id: "australia-sydney", label: "Sydney (UTC+10)", offset: 10 },
],
},
];
const zones = timezoneGroups.flatMap((group) => group.zones);
const durations = [15, 30, 45, 60];
// Host availability on Thursday, Oct 2, as minutes after midnight UTC.
const openingsUtc = [14 * 60, 15 * 60, 16 * 60 + 30, 18 * 60, 19 * 60 + 30];
function formatTime(minutes: number) {
const normalized = ((minutes % 1440) + 1440) % 1440;
const hours = Math.floor(normalized / 60);
const mins = normalized % 60;
const suffix = hours < 12 ? "AM" : "PM";
const displayHours = hours % 12 === 0 ? 12 : hours % 12;
const time = `${displayHours}:${mins.toString().padStart(2, "0")} ${suffix}`;
// Slots can land on the next or previous local day in far-off zones.
if (minutes >= 1440) return `${time} Fri`;
if (minutes < 0) return `${time} Wed`;
return time;
}
export default function NativeSelect13() {
const [zoneId, setZoneId] = React.useState("europe-berlin");
const [duration, setDuration] = React.useState(30);
const [slot, setSlot] = React.useState<number | null>(null);
const [booked, setBooked] = React.useState(false);
const zone = zones.find((item) => item.id === zoneId) ?? zones[0];
const toLocal = (utc: number) => utc + zone.offset * 60;
return (
<div className="grid w-full max-w-sm gap-5 rounded-xl border bg-card p-4 text-card-foreground">
<div className="grid gap-1">
<h3 className="text-base font-medium">Product demo with Lena Hart</h3>
<p className="text-sm text-muted-foreground">
Thursday, October 2 (UTC)
</p>
</div>
<div className="grid grid-cols-[minmax(0,1fr)_auto] gap-3">
<div className="grid min-w-0 gap-2">
<Label htmlFor="native-select-13-zone">
<Globe
aria-hidden="true"
className="size-4 text-muted-foreground"
/>
Time zone
</Label>
<NativeSelect
id="native-select-13-zone"
className="w-full"
value={zoneId}
onChange={(event) => {
setZoneId(event.target.value);
setSlot(null);
setBooked(false);
}}
>
{timezoneGroups.map((group) => (
<NativeSelectOptGroup key={group.label} label={group.label}>
{group.zones.map((item) => (
<NativeSelectOption key={item.id} value={item.id}>
{item.label}
</NativeSelectOption>
))}
</NativeSelectOptGroup>
))}
</NativeSelect>
</div>
<div className="grid gap-2">
<Label htmlFor="native-select-13-duration">
<Clock
aria-hidden="true"
className="size-4 text-muted-foreground"
/>
Length
</Label>
<NativeSelect
id="native-select-13-duration"
value={duration}
onChange={(event) => {
setDuration(Number(event.target.value));
setBooked(false);
}}
>
{durations.map((minutes) => (
<NativeSelectOption key={minutes} value={minutes}>
{minutes} min
</NativeSelectOption>
))}
</NativeSelect>
</div>
</div>
<fieldset className="grid gap-2">
<legend className="mb-2 text-sm font-medium">Available times</legend>
<div className="grid grid-cols-2 gap-2">
{openingsUtc.map((utc) => {
const selected = slot === utc;
return (
<Button
key={utc}
type="button"
variant={selected ? "default" : "outline"}
aria-pressed={selected}
className="tabular-nums"
onClick={() => {
setSlot(utc);
setBooked(false);
}}
>
{formatTime(toLocal(utc))}
</Button>
);
})}
</div>
</fieldset>
<p className="text-sm text-muted-foreground" aria-live="polite">
{slot === null ? (
"Pick a time to continue."
) : (
<>
<span className="font-medium text-foreground tabular-nums">
{formatTime(toLocal(slot))} –{" "}
{formatTime(toLocal(slot) + duration)}
</span>{" "}
in {zone.label.split(" (")[0]}
{booked ? ". Invite sent to your inbox." : null}
</>
)}
</p>
<Button
type="button"
disabled={slot === null || booked}
onClick={() => setBooked(true)}
>
{booked ? <CalendarCheck aria-hidden="true" /> : null}
{booked ? "Booked" : "Confirm booking"}
</Button>
</div>
);
}
npx shadcn@latest add @sevenui/component/native-select-13pnpm dlx shadcn@latest add @sevenui/component/native-select-13yarn dlx shadcn@latest add @sevenui/component/native-select-13bunx --bun shadcn@latest add @sevenui/component/native-select-13"use client";
import { Check, ShoppingBag, Truck } from "lucide-react";
import * as React from "react";
import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label";
import {
NativeSelect,
NativeSelectOption,
} from "@/components/ui/native-select";
const colors = [
{ value: "oat", label: "Oat" },
{ value: "charcoal", label: "Charcoal" },
{ value: "forest", label: "Forest" },
];
const sizes = ["XS", "S", "M", "L", "XL"];
// Units left per color and size.
const stock: Record<string, Record<string, number>> = {
oat: { XS: 4, S: 12, M: 9, L: 2, XL: 0 },
charcoal: { XS: 0, S: 6, M: 1, L: 8, XL: 5 },
forest: { XS: 3, S: 0, M: 0, L: 7, XL: 11 },
};
const quantities = [1, 2, 3, 4, 5];
const price = 128;
const currency = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
});
export default function NativeSelect14() {
const [color, setColor] = React.useState("oat");
const [size, setSize] = React.useState("");
const [quantity, setQuantity] = React.useState(1);
const [added, setAdded] = React.useState(false);
const available = size ? stock[color][size] : 0;
const maxQuantity = Math.min(available, 5);
function changeColor(next: string) {
setColor(next);
setAdded(false);
if (size && stock[next][size] === 0) {
setSize("");
}
setQuantity(1);
}
return (
<form
className="grid w-full max-w-sm gap-4 rounded-xl border bg-card p-4 text-card-foreground"
onSubmit={(event) => {
event.preventDefault();
setAdded(true);
}}
>
<div className="flex gap-4">
<img
src="/placeholder.svg"
alt="Merino crew sweater"
className="size-20 shrink-0 rounded-lg bg-muted object-cover"
/>
<div className="grid content-start gap-1">
<h3 className="text-base font-medium">Merino crew sweater</h3>
<p className="text-sm text-muted-foreground">
Midweight, machine washable
</p>
<p className="font-medium tabular-nums">{currency.format(price)}</p>
</div>
</div>
<div className="grid gap-3 sm:grid-cols-2">
<div className="grid gap-2">
<Label htmlFor="native-select-14-color">Color</Label>
<NativeSelect
id="native-select-14-color"
className="w-full"
value={color}
onChange={(event) => changeColor(event.target.value)}
>
{colors.map((item) => (
<NativeSelectOption key={item.value} value={item.value}>
{item.label}
</NativeSelectOption>
))}
</NativeSelect>
</div>
<div className="grid gap-2">
<Label htmlFor="native-select-14-size">Size</Label>
<NativeSelect
id="native-select-14-size"
className="w-full"
required
value={size}
onChange={(event) => {
setSize(event.target.value);
setQuantity(1);
setAdded(false);
}}
>
<NativeSelectOption value="" disabled>
Choose size
</NativeSelectOption>
{sizes.map((item) => {
const units = stock[color][item];
return (
<NativeSelectOption
key={item}
value={item}
disabled={units === 0}
>
{units === 0
? `${item} · sold out`
: units <= 2
? `${item} · ${units} left`
: item}
</NativeSelectOption>
);
})}
</NativeSelect>
</div>
</div>
<div className="flex items-end gap-3">
<div className="grid gap-2">
<Label htmlFor="native-select-14-qty">Quantity</Label>
<NativeSelect
id="native-select-14-qty"
disabled={!size}
value={quantity}
onChange={(event) => {
setQuantity(Number(event.target.value));
setAdded(false);
}}
>
{quantities
.filter((option) => option <= Math.max(maxQuantity, 1))
.map((option) => (
<NativeSelectOption key={option} value={option}>
{option}
</NativeSelectOption>
))}
</NativeSelect>
</div>
<Button type="submit" className="flex-1" disabled={!size}>
{added ? (
<Check aria-hidden="true" />
) : (
<ShoppingBag aria-hidden="true" />
)}
{added
? "Added to bag"
: `Add · ${currency.format(price * quantity)}`}
</Button>
</div>
<p
className="flex items-center gap-1.5 text-sm text-muted-foreground"
aria-live="polite"
>
<Truck aria-hidden="true" className="size-4 shrink-0" />
{!size
? "Select a size to check availability."
: available <= 2
? `Only ${available} left in ${size}. Ships tomorrow.`
: "In stock. Free shipping, arrives in 2–4 days."}
</p>
</form>
);
}
npx shadcn@latest add @sevenui/component/native-select-14pnpm dlx shadcn@latest add @sevenui/component/native-select-14yarn dlx shadcn@latest add @sevenui/component/native-select-14bunx --bun shadcn@latest add @sevenui/component/native-select-14