<script setup>
import { ref } from "vue";
import { Select } from "@dicehub/kappa/components/select";
const region = ref(["eu-central"]);
const regions = [
{ label: "EU Central · Frankfurt", value: "eu-central" },
{ label: "EU West · Dublin", value: "eu-west" },
{ label: "US East · Virginia", value: "us-east" },
];
</script>
<template>
<Select
v-model="region"
:items="regions"
label="Compute region"
description="Routes the run to the selected cluster."
name="compute-region"
placeholder="Select a region"
/>
</template>Installation
Select is part of the published Kappa package. Use the barrel import for a shared component surface or the granular path for a smaller feature boundary.
Barrel
import { Select, createSelectCollection } from "@dicehub/kappa";Granular
import {
Select,
createSelectCollection,
} from "@dicehub/kappa/components/select";Usage
Pass items for object records with label, value, and optional disabled. Pass an Ark ListCollection when you need custom mappers, groups, or a hand-authored list. The convenience root renders the trigger, popup, option rows, and one native HiddenSelect.
<script setup>
import { ref } from "vue";
import { Select } from "@dicehub/kappa/components/select";
const value = ref(["openfoam"]);
const formats = [
{ label: "OpenFOAM mesh", value: "openfoam" },
{ label: "Binary mesh", value: "binary" },
{ label: "Fluent mesh", value: "fluent" },
{ label: "STAR-CCM+ mesh", value: "star", disabled: true },
];
</script>
<template>
<Select
v-model="value"
:items="formats"
label="Mesh format"
name="mesh-format"
placeholder="Select a format"
/>
</template>Ark models both single and multiple selection as string[]; single-select state contains zero or one value. For a custom composition, put parts inside the root and do not add a second hidden select. Use RootProvider only when you already own an Ark machine and need to share it across a view.
Composition
Select.Root
├── Select.Label
├── Select.Control
│ └── Select.Trigger
│ ├── Select.ValueText
│ └── Select.Indicator
├── Select.Positioner + Teleport
│ └── Select.Content
│ └── Select.List
│ ├── Select.Group
│ │ ├── Select.GroupLabel
│ │ └── Select.Option
│ │ ├── Select.ItemText
│ │ └── Select.ItemIndicator
│ └── Select.Separator
└── Select.HiddenSelect (automatic)Ark UI Select owns the state machine, collection lookup, typeahead, keyboard focus, selection, dismissal, and ARIA attributes. Kappa owns the compound names, semantic tokens, field convenience props, popup teleport, and visual states.
SelectandSelect.Rootare the same convenience root.Select.Optionis a readable alias for Ark-backedSelect.Item.Positionerteleports tobodyby default; set:teleport="false"for in-place rendering.alignItemWithTriggeris a Kappa placement extension because Ark UI has no matching option. Ark still owns selection and focus; Kappa returns to normal anchored placement when alignment would cross the viewport padding.Listrenders collection items by default. Set:render-items="false"when grouping or ordering rows yourself.- Use
as-childon a part only when the replacement element preserves its role, focus, and keyboard contract. - The convenience root adds one
HiddenSelectfor forms. Do not render another one in the same root.
<script setup>
import { ref } from "vue";
import {
Select,
createSelectCollection,
} from "@dicehub/kappa/components/select";
const solver = ref(["gamg"]);
const solvers = [
{ label: "GAMG", value: "gamg", group: "Pressure" },
{ label: "PCG", value: "pcg", group: "Pressure" },
{ label: "PBiCGStab", value: "pbicgstab", group: "Momentum" },
{ label: "smoothSolver", value: "smooth", group: "Momentum" },
{ label: "diagonal", value: "diagonal", group: "Direct" },
];
const collection = createSelectCollection({
items: solvers,
groupBy: (item) => item.group,
itemToString: (item) => item.label,
itemToValue: (item) => item.value,
});
</script>
<template>
<Select v-model="solver" :collection="collection">
<template #default="{ collection: visibleCollection }">
<Select.Label>Linear solver</Select.Label>
<Select.Control>
<Select.Trigger>
<Select.ValueText placeholder="Select a solver" />
<Select.Indicator />
</Select.Trigger>
</Select.Control>
<Select.Positioner>
<Select.Content>
<Select.List :render-items="false">
<Select.Group v-for="[group, items] in visibleCollection.group()" :key="group">
<Select.GroupLabel>{{ group }}</Select.GroupLabel>
<Select.Option v-for="item in items" :key="item.value" :item="item">
{{ item.label }}
</Select.Option>
</Select.Group>
</Select.List>
</Select.Content>
</Select.Positioner>
</template>
</Select>
</template>Examples
Grouped options
Render filtered collection groups while keeping Ark's active option and keyboard state.
<script setup>
import { ref } from "vue";
import {
Select,
createSelectCollection,
} from "@dicehub/kappa/components/select";
const solver = ref(["gamg"]);
const solvers = [
{ label: "GAMG", value: "gamg", group: "Pressure" },
{ label: "PCG", value: "pcg", group: "Pressure" },
{ label: "PBiCGStab", value: "pbicgstab", group: "Momentum" },
{ label: "smoothSolver", value: "smooth", group: "Momentum" },
{ label: "diagonal", value: "diagonal", group: "Direct" },
];
const collection = createSelectCollection({
items: solvers,
groupBy: (item) => item.group,
itemToString: (item) => item.label,
itemToValue: (item) => item.value,
});
</script>
<template>
<Select v-model="solver" :collection="collection">
<template #default="{ collection: visibleCollection }">
<Select.Label>Linear solver</Select.Label>
<Select.Control>
<Select.Trigger>
<Select.ValueText placeholder="Select a solver" />
<Select.Indicator />
</Select.Trigger>
</Select.Control>
<Select.Positioner>
<Select.Content>
<Select.List :render-items="false">
<Select.Group v-for="[group, items] in visibleCollection.group()" :key="group">
<Select.GroupLabel>{{ group }}</Select.GroupLabel>
<Select.Option v-for="item in items" :key="item.value" :item="item">
{{ item.label }}
</Select.Option>
</Select.Group>
</Select.List>
</Select.Content>
</Select.Positioner>
</template>
</Select>
</template>Multiple values
Keep selected rows identifiable with check marks while only the active row receives a highlight.
<script setup>
import { ref } from "vue";
import { Select } from "@dicehub/kappa/components/select";
const selectedColumns = ref(["name", "location", "size"]);
const columns = [
{ label: "Name", value: "name" },
{ label: "Location", value: "location" },
{ label: "Size", value: "size" },
{ label: "Read", value: "read" },
{ label: "Write", value: "write" },
{ label: "Created at", value: "created-at" },
];
</script>
<template>
<Select
v-model="selectedColumns"
:items="columns"
label="Visible columns"
multiple
name="visible-columns"
placeholder="Select columns"
/>
</template>Placement
Set Ark's placement and gutter through the positioning prop. These examples disable collision flipping so each position stays visible.
<script setup>
import { Select } from "@dicehub/kappa/components/select";
const planets = [
{ label: "Mercury", value: "mercury" },
{ label: "Venus", value: "venus" },
{ label: "Earth", value: "earth" },
{ label: "Mars", value: "mars" },
];
</script>
<template>
<Select
:default-value="['earth']"
:items="planets"
:positioning="{ flip: false, placement: 'bottom-start' }"
label="bottom-start (default)"
/>
<Select
:default-value="['earth']"
:items="planets"
:positioning="{ flip: false, placement: 'top-start' }"
label="top-start"
/>
<Select
:default-value="['earth']"
:items="planets"
:positioning="{ flip: false, placement: 'bottom-end' }"
label="bottom-end"
/>
<Select
:default-value="['earth']"
:items="planets"
:positioning="{ flip: false, gutter: 12, placement: 'bottom-start' }"
label="gutter: 12"
/>
</template>Aligned to the selected option
Overlay the selected option on the trigger when space permits. Kappa falls back to anchored placement near a viewport edge.
<script setup>
import { ref } from "vue";
import { Select } from "@dicehub/kappa/components/select";
const anchoredPlanet = ref(["mars"]);
const alignedPlanet = ref(["mars"]);
const planets = [
{ label: "Mercury", value: "mercury" },
{ label: "Venus", value: "venus" },
{ label: "Earth", value: "earth" },
{ label: "Mars", value: "mars" },
{ label: "Jupiter", value: "jupiter" },
{ label: "Saturn", value: "saturn" },
{ label: "Uranus", value: "uranus" },
{ label: "Neptune", value: "neptune" },
];
</script>
<template>
<Select
v-model="anchoredPlanet"
:items="planets"
aria-label="Anchored planet"
/>
<Select
v-model="alignedPlanet"
:items="planets"
align-item-with-trigger
aria-label="Aligned planet"
/>
</template>Sizes
Use the compact sizes for dense toolbars and the base size for form fields.
<script setup>
import { Select } from "@dicehub/kappa/components/select";
const options = [
{ label: "Option A", value: "a" },
{ label: "Option B", value: "b" },
];
</script>
<template>
<div v-for="size in ['xs', 'sm', 'base', 'lg']" :key="size">
<span>{{ size }}</span>
<Select
:size="size"
:items="options"
:aria-label="`Select size ${size}`"
placeholder="Choose..."
/>
</div>
</template>Disabled, read-only, and invalid
Keep unavailable controls explicit and connect errors to the trigger.
<script setup>
import { Select } from "@dicehub/kappa/components/select";
const formats = [
{ label: "OpenFOAM mesh", value: "openfoam" },
{ label: "Binary mesh", value: "binary" },
{ label: "Fluent mesh", value: "fluent" },
];
</script>
<template>
<Select :items="formats" disabled label="Source format" placeholder="Unavailable" />
<Select :items="formats" :default-value="['openfoam']" read-only label="Pinned format" />
<Select :items="formats" error="Select one supported output format." label="Output format" required />
</template>Controlled value
Drive the selected value from Vue state and expose it to a live output.
<script setup>
import { ref } from "vue";
import { Select } from "@dicehub/kappa/components/select";
const region = ref(["eu-west"]);
const regions = [
{ label: "EU Central · Frankfurt", value: "eu-central" },
{ label: "EU West · Dublin", value: "eu-west" },
{ label: "US East · Virginia", value: "us-east" },
];
</script>
<template>
<Select v-model="region" :items="regions" label="Failover region" />
<output aria-live="polite">Controlled value: {{ region[0] }}</output>
</template>Long list (scrolling test)
Use the bounded popup for long collections. Scrolling stays inside the list without page bounce.
<script setup>
import { ref } from "vue";
import { Select } from "@dicehub/kappa/components/select";
const value = ref([]);
const options = Array.from({ length: 50 }, (_, index) => ({
label: `Option ${String(index + 1).padStart(2, "0")}`,
value: `option-${index + 1}`,
}));
</script>
<template>
<Select
v-model="value"
:items="options"
label="Long list select"
description="Tests scrolling behavior with many options."
placeholder="Choose an option"
/>
</template>Right to left
Ark locale direction and Kappa logical geometry support right-to-left interfaces.
<script setup>
import { Select } from "@dicehub/kappa/components/select";
const regions = [
{ label: "فرانكفورت · أوروبا الوسطى", value: "eu-central" },
{ label: "دبلن · أوروبا الغربية", value: "eu-west" },
{ label: "فرجينيا · شرق الولايات المتحدة", value: "us-east" },
];
</script>
<template>
<Select dir="rtl" :items="regions" label="منطقة الحساب" placeholder="اختر منطقة" />
</template>Accessibility
- Give the root a visible
Labelor an explicitaria-label. - Tab focuses the trigger. Enter, Space, or Arrow Down opens the popup; Arrow Up opens it with the last option highlighted.
- Arrow keys move through enabled options. Type characters for typeahead, Enter to select, and Escape to close and restore focus.
- Disabled options remain visible and are skipped by Ark keyboard navigation. Read-only controls stay focusable but do not change value.
descriptionanderrorconnect to the trigger througharia-describedby; errors also setaria-invalid.- The hidden native select carries
name,required, and form reset semantics. Keep option values stable and unique. - Direction follows the nearest Ark locale or the root
dir. Kappa uses logical CSS and stops popup motion under reduced-motion preferences.
See the official Ark UI Select documentationfor the primitive behavior and accessibility contract.
API Reference
Select.Root
| Prop | Type | Default | Description |
|---|---|---|---|
alignItemWithTrigger | boolean | false | Center the selected option over the trigger when viewport space permits. |
items | readonly T[] | [] | Convenience collection. Objects may expose label, value, and disabled. |
collection | ListCollection<T> | generated | Ark collection for custom item mapping, grouping, and advanced rendering. |
modelValue | string[] | undefined | Controlled selected values. A single-select value uses a one-item array internally. |
defaultValue | string[] | [] | Initial selected values for uncontrolled usage. |
multiple | boolean | false | Allow more than one option and keep the popup open after selection by default. |
open / defaultOpen | boolean | false | Control or initialize popup visibility. |
disabled | boolean | false | Prevent focus, opening, and selection. |
readOnly | boolean | false | Keep the value visible while preventing changes. |
invalid | boolean | false | Mark the control invalid. error also enables this state. |
required | boolean | false | Apply required form semantics to the hidden native select. |
label / description / error | string | undefined | Convenience field content with label and description/error relationships. |
itemToString / itemToValue / isItemDisabled | function | object defaults | Map custom collection records to accessible text, values, and disabled state. |
size | 'xs' | 'sm' | 'base' | 'lg' | 'base' | Kappa control geometry. |
positioning | Ark PositioningOptions | same width, bottom-start | Forwarded Ark floating-position options. |
dir | 'ltr' | 'rtl' | inherited | Locale direction used by Ark keyboard and placement behavior. |
Select.Item / Select.Option
| Prop | Type | Default | Description |
|---|---|---|---|
item | T | undefined | Collection item. Preferred for object collections. |
value | T | undefined | Resolve an item by value from the nearest collection. |
persistFocus | boolean | false | Keep focus on the option after selection. |
asChild | boolean | false | Merge Ark item behavior into a custom element. |
Parts
| Part | Element | Description |
|---|---|---|
Select.Root / RootProvider | div | Own Ark state, collection, controlled values, and compound context. |
Select.Label | label | Names the trigger and links it to the field. |
Select.Control / Trigger | div / button | The focusable combobox trigger and its visual control. |
Select.ValueText / Indicator | span / div | Selected label, placeholder, and disclosure indicator. |
Select.Positioner / Content | div | Teleported floating surface with Ark positioning. |
Select.List / Option | div | Collection list and selectable options. |
Select.ItemText / ItemIndicator | span | Accessible option text and selected mark. |
Select.Group / GroupLabel | div | Optional semantic grouping for related options. |
Select.Separator | div | Optional semantic divider between option groups. |
Select.ClearTrigger | button | Clears selected values when the composition includes it. |
Select.HiddenSelect | select | Native form bridge. The convenience root adds it automatically. |
Select.Context / ItemContext | slot | Expose Ark state for advanced render logic. |
Events
| Event | Payload | Description |
|---|---|---|
update:modelValue | string[] | Controlled selected values changed. |
valueChange | SelectValueChangeDetails | Ark selection details. |
update:open / openChange | boolean / SelectOpenChangeDetails | Popup visibility changed. |
update:highlightedValue / highlightChange | string / SelectHighlightChangeDetails | Active option changed. |
select | SelectSelectionDetails | An option was selected. |
focusOutside / interactOutside / pointerDownOutside | Ark outside event | The popup interacted with or lost focus outside. |
Exports
| Export | Description |
|---|---|
Select | Namespace and convenience root with all compound parts. |
SelectRoot / SelectOption | Named root and option aliases. |
createSelectCollection | Ark ListCollection factory for custom records and groups. |
SelectProps / SelectEmits / SelectSlots | Kappa root contracts. |
SelectSelectionDetails | Typed payload for the select event, derived from Ark RootEmits. |
SelectRootProvider / SelectApi | Advanced shared Ark machine composition. |
SELECT_SIZES / SELECT_DEFAULT_SIZE | Supported Kappa size values. |
selectAnatomy / useSelect / useSelectContext | Ark UI behavior and anatomy exports. |