"use client"
import { Portal, Select, createListCollection } from "@chakra-ui/react"
const Demo = () => {
return (
<Select.Root collection={frameworks} size="sm" width="320px">
<Select.HiddenSelect />
<Select.Label>Select framework</Select.Label>
<Select.Control>
<Select.Trigger>
<Select.ValueText placeholder="Select framework" />
</Select.Trigger>
<Select.IndicatorGroup>
<Select.Indicator />
</Select.IndicatorGroup>
</Select.Control>
<Portal>
<Select.Positioner>
<Select.Content>
{frameworks.items.map((framework) => (
<Select.Item item={framework} key={framework.value}>
{framework.label}
<Select.ItemIndicator />
</Select.Item>
))}
</Select.Content>
</Select.Positioner>
</Portal>
</Select.Root>
)
}
const frameworks = createListCollection({
items: [
{ label: "React.js", value: "react" },
{ label: "Vue.js", value: "vue" },
{ label: "Angular", value: "angular" },
{ label: "Svelte", value: "svelte" },
],
})
用法
import { Select } from "@chakra-ui/react"
<Select.Root>
<Select.HiddenSelect />
<Select.Label />
<Select.Control>
<Select.Trigger>
<Select.ValueText />
</Select.Trigger>
<Select.IndicatorGroup>
<Select.Indicator />
<Select.ClearTrigger />
</Select.IndicatorGroup>
</Select.Control>
<Select.Positioner>
<Select.Content>
<Select.Item />
<Select.ItemGroup>
<Select.ItemGroupLabel />
<Select.Item />
</Select.ItemGroup>
</Select.Content>
</Select.Positioner>
</Select.Root>
示例
尺寸
使用 size
属性来改变 select 组件的尺寸。
"use client"
import {
For,
Portal,
Select,
Stack,
createListCollection,
} from "@chakra-ui/react"
const Demo = () => {
return (
<Stack gap="5" width="320px">
<For each={["xs", "sm", "md", "lg"]}>
{(size) => (
<Select.Root key={size} size={size} collection={frameworks}>
<Select.HiddenSelect />
<Select.Label>size = {size}</Select.Label>
<Select.Control>
<Select.Trigger>
<Select.ValueText placeholder="Select framework" />
</Select.Trigger>
<Select.IndicatorGroup>
<Select.Indicator />
</Select.IndicatorGroup>
</Select.Control>
<Portal>
<Select.Positioner>
<Select.Content>
{frameworks.items.map((framework) => (
<Select.Item item={framework} key={framework.value}>
{framework.label}
<Select.ItemIndicator />
</Select.Item>
))}
</Select.Content>
</Select.Positioner>
</Portal>
</Select.Root>
)}
</For>
</Stack>
)
}
const frameworks = createListCollection({
items: [
{ label: "React.js", value: "react" },
{ label: "Vue.js", value: "vue" },
{ label: "Angular", value: "angular" },
{ label: "Svelte", value: "svelte" },
],
})
变体
使用 variant
属性来改变 select 组件的外观。
"use client"
import {
For,
Portal,
Select,
Stack,
createListCollection,
} from "@chakra-ui/react"
const Demo = () => {
return (
<Stack gap="5" width="320px">
<For each={["outline", "subtle"]}>
{(variant) => (
<Select.Root key={variant} variant={variant} collection={frameworks}>
<Select.HiddenSelect />
<Select.Label>Select framework - {variant}</Select.Label>
<Select.Control>
<Select.Trigger>
<Select.ValueText placeholder="Select framework" />
</Select.Trigger>
<Select.IndicatorGroup>
<Select.Indicator />
</Select.IndicatorGroup>
</Select.Control>
<Portal>
<Select.Positioner>
<Select.Content>
{frameworks.items.map((framework) => (
<Select.Item item={framework} key={framework.value}>
{framework.label}
<Select.ItemIndicator />
</Select.Item>
))}
</Select.Content>
</Select.Positioner>
</Portal>
</Select.Root>
)}
</For>
</Stack>
)
}
const frameworks = createListCollection({
items: [
{ label: "React.js", value: "react" },
{ label: "Vue.js", value: "vue" },
{ label: "Angular", value: "angular" },
{ label: "Svelte", value: "svelte" },
],
})
选项组
使用 Select.ItemGroup
组件对选择选项进行分组。
"use client"
import { Portal, Select, createListCollection } from "@chakra-ui/react"
import { groupBy } from "es-toolkit"
const Demo = () => {
return (
<Select.Root collection={collection} size="sm" width="320px">
<Select.HiddenSelect />
<Select.Label>Select framework</Select.Label>
<Select.Control>
<Select.Trigger>
<Select.ValueText placeholder="Select framework" />
</Select.Trigger>
<Select.IndicatorGroup>
<Select.Indicator />
</Select.IndicatorGroup>
</Select.Control>
<Portal>
<Select.Positioner>
<Select.Content>
{categories.map(([category, items]) => (
<Select.ItemGroup key={category}>
<Select.ItemGroupLabel>{category}</Select.ItemGroupLabel>
{items.map((item) => (
<Select.Item item={item} key={item.value}>
{item.label}
<Select.ItemIndicator />
</Select.Item>
))}
</Select.ItemGroup>
))}
</Select.Content>
</Select.Positioner>
</Portal>
</Select.Root>
)
}
const collection = createListCollection({
items: [
{ label: "Naruto", value: "naruto", category: "Anime" },
{ label: "One Piece", value: "one-piece", category: "Anime" },
{ label: "Dragon Ball", value: "dragon-ball", category: "Anime" },
{
label: "The Shawshank Redemption",
value: "the-shawshank-redemption",
category: "Movies",
},
{ label: "The Godfather", value: "the-godfather", category: "Movies" },
{ label: "The Dark Knight", value: "the-dark-knight", category: "Movies" },
],
})
const categories = Object.entries(
groupBy(collection.items, (item) => item.category),
)
受控
使用 value
和 onValueChange
属性来控制 select 组件。
"use client"
import { Portal, Select, createListCollection } from "@chakra-ui/react"
import { useState } from "react"
const Demo = () => {
const [value, setValue] = useState<string[]>([])
return (
<Select.Root
collection={frameworks}
width="320px"
value={value}
onValueChange={(e) => setValue(e.value)}
>
<Select.HiddenSelect />
<Select.Label>Select framework</Select.Label>
<Select.Control>
<Select.Trigger>
<Select.ValueText placeholder="Select framework" />
</Select.Trigger>
<Select.IndicatorGroup>
<Select.Indicator />
</Select.IndicatorGroup>
</Select.Control>
<Portal>
<Select.Positioner>
<Select.Content>
{frameworks.items.map((framework) => (
<Select.Item item={framework} key={framework.value}>
{framework.label}
<Select.ItemIndicator />
</Select.Item>
))}
</Select.Content>
</Select.Positioner>
</Portal>
</Select.Root>
)
}
const frameworks = createListCollection({
items: [
{ label: "React.js", value: "react" },
{ label: "Vue.js", value: "vue" },
{ label: "Angular", value: "angular" },
{ label: "Svelte", value: "svelte" },
],
})
异步加载
这是一个如何从远程源填充 select collection
的示例。
"use client"
import { Portal, Select, Spinner, createListCollection } from "@chakra-ui/react"
import { useMemo } from "react"
import { useAsync } from "react-use"
interface Pokemon {
name: string
url: string
}
const Demo = () => {
const state = useAsync(async (): Promise<Pokemon[]> => {
const response = await fetch("https://pokeapi.co/api/v2/pokemon")
const data = await response.json()
return data.results
}, [])
const collection = useMemo(() => {
return createListCollection({
items: state.value ?? [],
itemToString: (pokemon) => pokemon.name,
itemToValue: (pokemon) => pokemon.name,
})
}, [state.value])
return (
<Select.Root collection={collection} size="sm" width="320px">
<Select.HiddenSelect />
<Select.Label>Select pokemon</Select.Label>
<Select.Control>
<Select.Trigger>
<Select.ValueText placeholder="Select pokemon" />
</Select.Trigger>
<Select.IndicatorGroup>
{state.loading && (
<Spinner size="xs" borderWidth="1.5px" color="fg.muted" />
)}
<Select.Indicator />
</Select.IndicatorGroup>
</Select.Control>
<Portal>
<Select.Positioner>
<Select.Content>
{collection.items.map((pokemon) => (
<Select.Item item={pokemon} key={pokemon.name}>
{pokemon.name}
<Select.ItemIndicator />
</Select.Item>
))}
</Select.Content>
</Select.Positioner>
</Portal>
</Select.Root>
)
}
Hook Form
这是一个如何将 Select
组件与 react-hook-form
一起使用的示例。
"use client"
import {
Button,
Field,
Portal,
Select,
Stack,
createListCollection,
} from "@chakra-ui/react"
import { zodResolver } from "@hookform/resolvers/zod"
import { Controller, useForm } from "react-hook-form"
import { z } from "zod"
const formSchema = z.object({
framework: z.string({ message: "Framework is required" }).array(),
})
type FormValues = z.infer<typeof formSchema>
const Demo = () => {
const {
handleSubmit,
formState: { errors },
control,
} = useForm<FormValues>({
resolver: zodResolver(formSchema),
})
const onSubmit = handleSubmit((data) => console.log(data))
return (
<form onSubmit={onSubmit}>
<Stack gap="4" align="flex-start">
<Field.Root invalid={!!errors.framework} width="320px">
<Field.Label>Framework</Field.Label>
<Controller
control={control}
name="framework"
render={({ field }) => (
<Select.Root
name={field.name}
value={field.value}
onValueChange={({ value }) => field.onChange(value)}
onInteractOutside={() => field.onBlur()}
collection={frameworks}
>
<Select.HiddenSelect />
<Select.Control>
<Select.Trigger>
<Select.ValueText placeholder="Select framework" />
</Select.Trigger>
<Select.IndicatorGroup>
<Select.Indicator />
</Select.IndicatorGroup>
</Select.Control>
<Portal>
<Select.Positioner>
<Select.Content>
{frameworks.items.map((framework) => (
<Select.Item item={framework} key={framework.value}>
{framework.label}
<Select.ItemIndicator />
</Select.Item>
))}
</Select.Content>
</Select.Positioner>
</Portal>
</Select.Root>
)}
/>
<Field.ErrorText>{errors.framework?.message}</Field.ErrorText>
</Field.Root>
<Button size="sm" type="submit">
Submit
</Button>
</Stack>
</form>
)
}
const frameworks = createListCollection({
items: [
{ label: "React.js", value: "react" },
{ label: "Vue.js", value: "vue" },
{ label: "Angular", value: "angular" },
{ label: "Svelte", value: "svelte" },
],
})
禁用
使用 disabled
属性来禁用 select 组件。
"use client"
import { Portal, Select, createListCollection } from "@chakra-ui/react"
const Demo = () => {
return (
<Select.Root disabled collection={frameworks} size="sm" width="320px">
<Select.HiddenSelect />
<Select.Label>Select framework</Select.Label>
<Select.Control>
<Select.Trigger>
<Select.ValueText placeholder="Select framework" />
</Select.Trigger>
<Select.IndicatorGroup>
<Select.Indicator />
</Select.IndicatorGroup>
</Select.Control>
<Portal>
<Select.Positioner>
<Select.Content>
{frameworks.items.map((framework) => (
<Select.Item item={framework} key={framework.value}>
{framework.label}
<Select.ItemIndicator />
</Select.Item>
))}
</Select.Content>
</Select.Positioner>
</Portal>
</Select.Root>
)
}
const frameworks = createListCollection({
items: [
{ label: "React.js", value: "react" },
{ label: "Vue.js", value: "vue" },
{ label: "Angular", value: "angular" },
{ label: "Svelte", value: "svelte" },
],
})
无效
这是一个如何将 Select
组件与 Field
组件组合以显示错误状态的示例。
"use client"
import { Field, Portal, Select, createListCollection } from "@chakra-ui/react"
const Demo = () => {
return (
<Field.Root invalid>
<Select.Root collection={frameworks} size="sm" width="320px">
<Select.HiddenSelect />
<Select.Label>Select framework</Select.Label>
<Select.Control>
<Select.Trigger>
<Select.ValueText placeholder="Select framework" />
</Select.Trigger>
<Select.IndicatorGroup>
<Select.Indicator />
</Select.IndicatorGroup>
</Select.Control>
<Portal>
<Select.Positioner>
<Select.Content>
{frameworks.items.map((framework) => (
<Select.Item item={framework} key={framework.value}>
{framework.label}
<Select.ItemIndicator />
</Select.Item>
))}
</Select.Content>
</Select.Positioner>
</Portal>
</Select.Root>
<Field.ErrorText>This is an error</Field.ErrorText>
</Field.Root>
)
}
const frameworks = createListCollection({
items: [
{ label: "React.js", value: "react" },
{ label: "Vue.js", value: "vue" },
{ label: "Angular", value: "angular" },
{ label: "Svelte", value: "svelte" },
],
})
多选
使用 multiple
属性允许多选。
"use client"
import { Portal, Select, createListCollection } from "@chakra-ui/react"
const Demo = () => {
return (
<Select.Root multiple collection={frameworks} size="sm" width="320px">
<Select.HiddenSelect />
<Select.Label>Select framework</Select.Label>
<Select.Control>
<Select.Trigger>
<Select.ValueText placeholder="Select framework" />
</Select.Trigger>
<Select.IndicatorGroup>
<Select.Indicator />
</Select.IndicatorGroup>
</Select.Control>
<Portal>
<Select.Positioner>
<Select.Content>
{frameworks.items.map((framework) => (
<Select.Item item={framework} key={framework.value}>
{framework.label}
<Select.ItemIndicator />
</Select.Item>
))}
</Select.Content>
</Select.Positioner>
</Portal>
</Select.Root>
)
}
const frameworks = createListCollection({
items: [
{ label: "React.js", value: "react" },
{ label: "Vue.js", value: "vue" },
{ label: "Angular", value: "angular" },
{ label: "Svelte", value: "svelte" },
],
})
定位
使用 positioning
属性控制 select 组件底层 floating-ui
的选项。
"use client"
import { Portal, Select, createListCollection } from "@chakra-ui/react"
const Demo = () => {
return (
<Select.Root
collection={frameworks}
size="sm"
width="320px"
positioning={{ placement: "top", flip: false }}
>
<Select.HiddenSelect />
<Select.Label>Select framework</Select.Label>
<Select.Control>
<Select.Trigger>
<Select.ValueText placeholder="Select framework" />
</Select.Trigger>
<Select.IndicatorGroup>
<Select.Indicator />
</Select.IndicatorGroup>
</Select.Control>
<Portal>
<Select.Positioner>
<Select.Content>
{frameworks.items.map((framework) => (
<Select.Item item={framework} key={framework.value}>
{framework.label}
<Select.ItemIndicator />
</Select.Item>
))}
</Select.Content>
</Select.Positioner>
</Portal>
</Select.Root>
)
}
const frameworks = createListCollection({
items: [
{ label: "React.js", value: "react" },
{ label: "Vue.js", value: "vue" },
{ label: "Angular", value: "angular" },
{ label: "Svelte", value: "svelte" },
],
})
清除触发器
渲染 Select.ClearTrigger
组件以显示清除按钮。点击清除按钮将清除选定的值。
"use client"
import { Portal, Select, createListCollection } from "@chakra-ui/react"
const Demo = () => {
return (
<Select.Root
collection={animeMovies}
defaultValue={["spirited_away"]}
size="sm"
width="320px"
>
<Select.HiddenSelect />
<Select.Label>Select fav. anime</Select.Label>
<Select.Control>
<Select.Trigger>
<Select.ValueText placeholder="Select anime" />
</Select.Trigger>
<Select.IndicatorGroup>
<Select.ClearTrigger />
<Select.Indicator />
</Select.IndicatorGroup>
</Select.Control>
<Portal>
<Select.Positioner>
<Select.Content>
{animeMovies.items.map((anime) => (
<Select.Item item={anime} key={anime.value}>
{anime.label}
<Select.ItemIndicator />
</Select.Item>
))}
</Select.Content>
</Select.Positioner>
</Portal>
</Select.Root>
)
}
const animeMovies = createListCollection({
items: [
{ label: "Spirited Away", value: "spirited_away" },
{ label: "My Neighbor Totoro", value: "my_neighbor_totoro" },
{ label: "Akira", value: "akira" },
{ label: "Princess Mononoke", value: "princess_mononoke" },
{ label: "Grave of the Fireflies", value: "grave_of_the_fireflies" },
{ label: "Howl's Moving Castle", value: "howls_moving_castle" },
{ label: "Ghost in the Shell", value: "ghost_in_the_shell" },
{ label: "Naruto", value: "naruto" },
{ label: "Hunter x Hunter", value: "hunter_x_hunter" },
{ label: "The Wind Rises", value: "the_wind_rises" },
{ label: "Kiki's Delivery Service", value: "kikis_delivery_service" },
{ label: "Perfect Blue", value: "perfect_blue" },
{
label: "The Girl Who Leapt Through Time",
value: "the_girl_who_leapt_through_time",
},
{ label: "Weathering with You", value: "weathering_with_you" },
{ label: "Ponyo", value: "ponyo" },
{ label: "5 Centimeters per Second", value: "5_centimeters_per_second" },
{ label: "A Silent Voice", value: "a_silent_voice" },
{ label: "Paprika", value: "paprika" },
{ label: "Wolf Children", value: "wolf_children" },
{ label: "Redline", value: "redline" },
{
label: "The Tale of the Princess Kaguya",
value: "the_tale_of_the_princess_kaguya",
},
],
})
溢出
当选项过多时,由于设置了 maxHeight
,选项将溢出容器。
"use client"
import { Portal, Select, createListCollection } from "@chakra-ui/react"
const Demo = () => {
return (
<Select.Root collection={animeMovies} size="sm" width="240px">
<Select.HiddenSelect />
<Select.Label>Select anime</Select.Label>
<Select.Control>
<Select.Trigger>
<Select.ValueText placeholder="Select movie" />
</Select.Trigger>
<Select.IndicatorGroup>
<Select.Indicator />
</Select.IndicatorGroup>
</Select.Control>
<Portal>
<Select.Positioner>
<Select.Content>
{animeMovies.items.map((movie) => (
<Select.Item item={movie} key={movie.value}>
{movie.label}
<Select.ItemIndicator />
</Select.Item>
))}
</Select.Content>
</Select.Positioner>
</Portal>
</Select.Root>
)
}
const animeMovies = createListCollection({
items: [
{ label: "Spirited Away", value: "spirited_away" },
{ label: "My Neighbor Totoro", value: "my_neighbor_totoro" },
{ label: "Akira", value: "akira" },
{ label: "Princess Mononoke", value: "princess_mononoke" },
{ label: "Grave of the Fireflies", value: "grave_of_the_fireflies" },
{ label: "Howl's Moving Castle", value: "howls_moving_castle" },
{ label: "Ghost in the Shell", value: "ghost_in_the_shell" },
{ label: "Naruto", value: "naruto" },
{ label: "Hunter x Hunter", value: "hunter_x_hunter" },
{ label: "The Wind Rises", value: "the_wind_rises" },
{ label: "Kiki's Delivery Service", value: "kikis_delivery_service" },
{ label: "Perfect Blue", value: "perfect_blue" },
{
label: "The Girl Who Leapt Through Time",
value: "the_girl_who_leapt_through_time",
},
{ label: "Weathering with You", value: "weathering_with_you" },
{ label: "Ponyo", value: "ponyo" },
{ label: "5 Centimeters per Second", value: "5_centimeters_per_second" },
{ label: "A Silent Voice", value: "a_silent_voice" },
{ label: "Paprika", value: "paprika" },
{ label: "Wolf Children", value: "wolf_children" },
{ label: "Redline", value: "redline" },
{
label: "The Tale of the Princess Kaguya",
value: "the_tale_of_the_princess_kaguya",
},
],
})
项目描述
这是一个如何为每个项目渲染描述的示例。
"use client"
import {
Portal,
Select,
Span,
Stack,
createListCollection,
} from "@chakra-ui/react"
const Demo = () => {
return (
<Select.Root
collection={frameworks}
size="sm"
width="320px"
defaultValue={["pro"]}
>
<Select.HiddenSelect />
<Select.Label>Select plan</Select.Label>
<Select.Control>
<Select.Trigger>
<Select.ValueText placeholder="Select plan" />
</Select.Trigger>
<Select.IndicatorGroup>
<Select.Indicator />
</Select.IndicatorGroup>
</Select.Control>
<Portal>
<Select.Positioner>
<Select.Content>
{frameworks.items.map((framework) => (
<Select.Item item={framework} key={framework.value}>
<Stack gap="0">
<Select.ItemText>{framework.label}</Select.ItemText>
<Span color="fg.muted" textStyle="xs">
{framework.description}
</Span>
</Stack>
<Select.ItemIndicator />
</Select.Item>
))}
</Select.Content>
</Select.Positioner>
</Portal>
</Select.Root>
)
}
const frameworks = createListCollection({
items: [
{
label: "Basic Plan",
value: "basic",
description: "$9/month - Perfect for small projects",
},
{
label: "Pro Plan",
value: "pro",
description: "$29/month - Advanced features",
},
{
label: "Business Plan",
value: "business",
description: "$99/month - Enterprise-grade solutions",
},
{
label: "Enterprise Plan",
value: "enterprise",
description: "Custom pricing - Tailored solutions",
},
],
})
在弹出框内
这是一个如何在 Popover
组件内使用 Select
的示例。
"use client"
import {
Button,
Popover,
Portal,
Select,
createListCollection,
} from "@chakra-ui/react"
const Demo = () => {
return (
<Popover.Root size="xs">
<Popover.Trigger asChild>
<Button variant="outline" size="sm">
Select in Popover
</Button>
</Popover.Trigger>
<Portal>
<Popover.Positioner>
<Popover.Content>
<Popover.Header>Select in Popover</Popover.Header>
<Popover.Body>
<Select.Root
collection={frameworks}
size="sm"
positioning={{ sameWidth: true, placement: "bottom" }}
>
<Select.HiddenSelect />
<Select.Control>
<Select.Trigger>
<Select.ValueText placeholder="Select framework" />
</Select.Trigger>
<Select.IndicatorGroup>
<Select.Indicator />
</Select.IndicatorGroup>
</Select.Control>
<Select.Positioner>
<Select.Content width="full">
{frameworks.items.map((item) => (
<Select.Item item={item} key={item.value}>
{item.label}
<Select.ItemIndicator />
</Select.Item>
))}
</Select.Content>
</Select.Positioner>
</Select.Root>
</Popover.Body>
</Popover.Content>
</Popover.Positioner>
</Portal>
</Popover.Root>
)
}
const frameworks = createListCollection({
items: [
{ label: "React.js", value: "react" },
{ label: "Vue.js", value: "vue" },
{ label: "Angular", value: "angular" },
{ label: "Svelte", value: "svelte" },
],
})
在对话框内
要在 Dialog
内使用 Select
,您需要避免将 Select.Positioner
传送到文档主体。
-<Portal>
<Select.Positioner>
<Select.Content>
{/* ... */}
</Select.Content>
</Select.Positioner>
-</Portal>
"use client"
import {
Button,
CloseButton,
Dialog,
Portal,
Select,
createListCollection,
} from "@chakra-ui/react"
const Demo = () => {
return (
<Dialog.Root>
<Dialog.Trigger asChild>
<Button variant="outline">Open Dialog</Button>
</Dialog.Trigger>
<Portal>
<Dialog.Backdrop />
<Dialog.Positioner>
<Dialog.Content>
<Dialog.CloseTrigger asChild>
<CloseButton />
</Dialog.CloseTrigger>
<Dialog.Header>
<Dialog.Title>Select in Dialog</Dialog.Title>
</Dialog.Header>
<Dialog.Body>
<DialogSelect />
</Dialog.Body>
<Dialog.Footer />
</Dialog.Content>
</Dialog.Positioner>
</Portal>
</Dialog.Root>
)
}
const frameworks = createListCollection({
items: [
{ label: "React.js", value: "react" },
{ label: "Vue.js", value: "vue" },
{ label: "Angular", value: "angular" },
{ label: "Svelte", value: "svelte" },
],
})
function DialogSelect() {
return (
<Select.Root collection={frameworks} size="sm">
<Select.HiddenSelect />
<Select.Label>Select framework</Select.Label>
<Select.Control>
<Select.Trigger>
<Select.ValueText placeholder="Select framework" />
</Select.Trigger>
<Select.IndicatorGroup>
<Select.Indicator />
</Select.IndicatorGroup>
</Select.Control>
<Select.Positioner>
<Select.Content>
{frameworks.items.map((item) => (
<Select.Item item={item} key={item.value}>
{item.label}
</Select.Item>
))}
</Select.Content>
</Select.Positioner>
</Select.Root>
)
}
头像选择
这是一个如何组合 Select
和 Avatar
的示例。
"use client"
import {
Avatar,
HStack,
Select,
createListCollection,
useSelectContext,
} from "@chakra-ui/react"
const SelectValue = () => {
const select = useSelectContext()
const items = select.selectedItems as Array<{ name: string; avatar: string }>
const { name, avatar } = items[0]
return (
<Select.ValueText placeholder="Select member">
<HStack>
<Avatar.Root shape="rounded" size="2xs">
<Avatar.Image src={avatar} alt={name} />
<Avatar.Fallback name={name} />
</Avatar.Root>
{name}
</HStack>
</Select.ValueText>
)
}
const Demo = () => {
return (
<Select.Root
collection={members}
size="sm"
width="240px"
defaultValue={["jessica_jones"]}
positioning={{ sameWidth: true }}
>
<Select.HiddenSelect />
<Select.Label>Select member</Select.Label>
<Select.Control>
<Select.Trigger>
<SelectValue />
</Select.Trigger>
<Select.IndicatorGroup>
<Select.Indicator />
</Select.IndicatorGroup>
</Select.Control>
<Select.Positioner>
<Select.Content>
{members.items.map((item) => (
<Select.Item item={item} key={item.id} justifyContent="flex-start">
<Avatar.Root shape="rounded" size="2xs">
<Avatar.Image src={item.avatar} alt={item.name} />
<Avatar.Fallback name={item.name} />
</Avatar.Root>
{item.name}
<Select.ItemIndicator />
</Select.Item>
))}
</Select.Content>
</Select.Positioner>
</Select.Root>
)
}
const members = createListCollection({
items: [
{
name: "Jessica Jones",
id: "jessica_jones",
avatar:
"https://images.unsplash.com/photo-1531746020798-e6953c6e8e04?w=100",
},
{
name: "Kenneth Johnson",
id: "kenneth_johnson",
avatar:
"https://images.unsplash.com/photo-1523477800337-966dbabe060b?w=100",
},
{
name: "Kate Wilson",
id: "kate_wilson",
avatar:
"https://images.unsplash.com/photo-1609712409631-dbbb050746d1?w=100",
},
],
itemToString: (item) => item.name,
itemToValue: (item) => item.id,
})
国家选择
这是一个如何使用 Select
组件选择国家的示例。
"use client"
import { Portal, Select, createListCollection } from "@chakra-ui/react"
import { groupBy } from "es-toolkit"
const Demo = () => {
return (
<Select.Root
collection={countries}
size="sm"
width="320px"
defaultValue={["NG"]}
>
<Select.HiddenSelect />
<Select.Label>Select country</Select.Label>
<Select.Control>
<Select.Trigger>
<Select.ValueText placeholder="-" />
</Select.Trigger>
<Select.IndicatorGroup>
<Select.Indicator />
</Select.IndicatorGroup>
</Select.Control>
<Portal>
<Select.Positioner>
<Select.Content>
{continents.map(([continent, items]) => (
<Select.ItemGroup key={continent}>
<Select.ItemGroupLabel>{continent}</Select.ItemGroupLabel>
{items.map((item) => (
<Select.Item item={item} key={item.value}>
{countries.stringifyItem(item)}
<Select.ItemIndicator />
</Select.Item>
))}
</Select.ItemGroup>
))}
</Select.Content>
</Select.Positioner>
</Portal>
</Select.Root>
)
}
const countries = createListCollection({
items: [
{ value: "US", label: "United States", flag: "🇺🇸", continent: "America" },
{ value: "CA", label: "Canada", flag: "🇨🇦", continent: "America" },
{ value: "MX", label: "Mexico", flag: "🇲🇽", continent: "America" },
{ value: "BR", label: "Brazil", flag: "🇧🇷", continent: "America" },
{ value: "ZA", label: "South Africa", flag: "🇿🇦", continent: "Africa" },
{ value: "NG", label: "Nigeria", flag: "🇳🇬", continent: "Africa" },
{ value: "MA", label: "Morocco", flag: "🇲🇦", continent: "Africa" },
{ value: "EG", label: "Egypt", flag: "🇪🇬", continent: "Africa" },
{ value: "CN", label: "China", flag: "🇨🇳", continent: "Asia" },
{ value: "JP", label: "Japan", flag: "🇯🇵", continent: "Asia" },
{ value: "IN", label: "India", flag: "🇮🇳", continent: "Asia" },
{ value: "KR", label: "South Korea", flag: "🇰🇷", continent: "Asia" },
{ value: "GB", label: "United Kingdom", flag: "🇬🇧", continent: "Europe" },
{ value: "FR", label: "France", flag: "🇫🇷", continent: "Europe" },
{ value: "DE", label: "Germany", flag: "🇩🇪", continent: "Europe" },
{ value: "IT", label: "Italy", flag: "🇮🇹", continent: "Europe" },
{ value: "ES", label: "Spain", flag: "🇪🇸", continent: "Europe" },
{ value: "AU", label: "Australia", flag: "🇦🇺", continent: "Oceania" },
{ value: "NZ", label: "New Zealand", flag: "🇳🇿", continent: "Oceania" },
{ value: "FJ", label: "Fiji", flag: "🇫🇯", continent: "Oceania" },
],
itemToString: (item) => `${item.flag} ${item.label}`,
itemToValue: (item) => item.value,
})
const continents = Object.entries(
groupBy(countries.items, (item) => item.continent),
)
图标按钮
这是一个如何使用 IconButton
触发 select 组件的示例。
"use client"
import {
HStack,
IconButton,
Portal,
Select,
createListCollection,
useSelectContext,
} from "@chakra-ui/react"
import {
RiAngularjsLine,
RiForbidLine,
RiReactjsLine,
RiSvelteLine,
RiVuejsLine,
} from "react-icons/ri"
const SelectTrigger = () => {
const select = useSelectContext()
const items = select.selectedItems as Framework[]
return (
<IconButton
px="2"
variant="outline"
size="sm"
{...select.getTriggerProps()}
>
{select.hasSelectedItems ? items[0].icon : <RiForbidLine />}
</IconButton>
)
}
const Demo = () => {
return (
<Select.Root
positioning={{ sameWidth: false }}
collection={frameworks}
size="sm"
width="320px"
defaultValue={["react"]}
>
<Select.HiddenSelect />
<Select.Control>
<SelectTrigger />
</Select.Control>
<Portal>
<Select.Positioner>
<Select.Content minW="32">
{frameworks.items.map((framework) => (
<Select.Item item={framework} key={framework.value}>
<HStack>
{framework.icon}
{framework.label}
</HStack>
<Select.ItemIndicator />
</Select.Item>
))}
</Select.Content>
</Select.Positioner>
</Portal>
</Select.Root>
)
}
const frameworks = createListCollection({
items: [
{ label: "React.js", value: "react", icon: <RiReactjsLine /> },
{ label: "Vue.js", value: "vue", icon: <RiVuejsLine /> },
{ label: "Angular", value: "angular", icon: <RiAngularjsLine /> },
{ label: "Svelte", value: "svelte", icon: <RiSvelteLine /> },
],
})
interface Framework {
label: string
value: string
icon: React.ReactNode
}
属性
根
属性 | 默认 | 类型 |
---|---|---|
collection * | ListCollection<T> 项目集合 | |
closeOnSelect | true | boolean 选择项目后是否关闭选择器 |
composite | true | boolean 选择器是否与其他复合小部件(如选项卡或组合框)组合 |
lazyMount | false | boolean 是否启用延迟挂载 |
loopFocus | false | boolean 是否循环键盘导航选项 |
unmountOnExit | false | boolean 退出时是否卸载。 |
colorPalette | 'gray' | 'gray' | 'red' | 'orange' | 'yellow' | 'green' | 'teal' | 'blue' | 'cyan' | 'purple' | 'pink' 组件的调色板 |
variant | 'outline' | 'outline' | 'subtle' 组件的变体 |
size | 'md' | 'xs' | 'sm' | 'md' | 'lg' 组件的尺寸 |
asChild | ||
defaultOpen | boolean 选择器首次渲染时的初始打开状态。当您不需要控制其打开状态时使用。 | |
defaultValue | string[] 选择器首次渲染时的初始值。当您不需要控制选择器状态时使用。 | |
deselectable | boolean 是否可以通过点击选定项目来清除值。**注意:**这仅适用于单选。 | |
disabled | boolean 选择器是否被禁用 | |
form | string 底层选择器的关联表单。 | |
highlightedValue | string 高亮项目的键 | |
id | string 机器的唯一标识符。 | |
ids | Partial<{ root: string content: string control: string trigger: string clearTrigger: string label: string hiddenSelect: string positioner: string item(id: string | number): string itemGroup(id: string | number): string itemGroupLabel(id: string | number): string }> 选择器中元素的 ID。用于组合。 | |
immediate | boolean 是否立即同步当前更改或将其推迟到下一帧 | |
invalid | boolean 选择器是否无效 | |
multiple | boolean 是否允许多选 | |
name | string 底层选择器的 `name` 属性。 | |
onExitComplete | () => void 在关闭状态动画结束时调用的函数 | |
onFocusOutside | (event: FocusOutsideEvent) => void 焦点移到组件外部时调用的函数 | |
onHighlightChange | (details: HighlightChangeDetails<T>) => void 高亮项目更改时触发的回调。 | |
onInteractOutside | (event: InteractOutsideEvent) => void 在组件外部发生交互时调用的函数 | |
onOpenChange | (details: OpenChangeDetails) => void 弹出窗口打开时调用的函数 | |
onPointerDownOutside | (event: PointerDownOutsideEvent) => void 指针在组件外部按下时调用的函数 | |
onValueChange | (details: ValueChangeDetails<T>) => void 选定项目更改时触发的回调。 | |
open | boolean 选择菜单是否打开 | |
positioning | PositioningOptions 菜单的定位选项。 | |
present | boolean 节点是否存在(由用户控制) | |
readOnly | boolean 选择器是否只读 | |
required | boolean 选择器是否为必填 | |
scrollToIndexFn | (details: ScrollToIndexDetails) => void 滚动到特定索引的函数 | |
value | string[] 选定项目的键 | |
as | React.ElementType 要渲染的底层元素。 | |
unstyled | boolean 是否移除组件样式。 |