コンテンツにスキップ

セレクト

ユーザーが選択できるオプションのリストを、ボタンでトリガーして表示します。
vue
<script setup lang="ts">
import { Icon } from '@iconify/vue'
import { ref } from 'vue'
import {
  SelectContent,
  SelectGroup,
  SelectItem,
  SelectItemIndicator,
  SelectItemText,
  SelectLabel,
  SelectPortal,
  SelectRoot,
  SelectScrollDownButton,
  SelectScrollUpButton,
  SelectSeparator,
  SelectTrigger,
  SelectValue,
  SelectViewport,
} from 'radix-vue'

const fruit = ref()

const options = ['Apple', 'Banana', 'Blueberry', 'Grapes', 'Pineapple']
const vegetables = ['Aubergine', 'Broccoli', 'Carrot', 'Courgette', 'Leek']
</script>

<template>
  <SelectRoot v-model="fruit">
    <SelectTrigger
      class="inline-flex min-w-[160px] items-center justify-between rounded px-[15px] text-[13px] leading-none h-[35px] gap-[5px] bg-white text-grass11 shadow-[0_2px_10px] shadow-black/10 hover:bg-mauve3 focus:shadow-[0_0_0_2px] focus:shadow-black data-[placeholder]:text-green9 outline-none"
      aria-label="Customise options"
    >
      <SelectValue placeholder="Select a fruit..." />
      <Icon
        icon="radix-icons:chevron-down"
        class="h-3.5 w-3.5"
      />
    </SelectTrigger>

    <SelectPortal>
      <SelectContent
        class="min-w-[160px] bg-white rounded shadow-[0px_10px_38px_-10px_rgba(22,_23,_24,_0.35),_0px_10px_20px_-15px_rgba(22,_23,_24,_0.2)] will-change-[opacity,transform] data-[side=top]:animate-slideDownAndFade data-[side=right]:animate-slideLeftAndFade data-[side=bottom]:animate-slideUpAndFade data-[side=left]:animate-slideRightAndFade z-[100]"
        :side-offset="5"
      >
        <SelectScrollUpButton class="flex items-center justify-center h-[25px] bg-white text-violet11 cursor-default">
          <Icon icon="radix-icons:chevron-up" />
        </SelectScrollUpButton>

        <SelectViewport class="p-[5px]">
          <SelectLabel class="px-[25px] text-xs leading-[25px] text-mauve11">
            Fruits
          </SelectLabel>
          <SelectGroup>
            <SelectItem
              v-for="(option, index) in options"
              :key="index"
              class="text-[13px] leading-none text-grass11 rounded-[3px] flex items-center h-[25px] pr-[35px] pl-[25px] relative select-none data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none data-[highlighted]:outline-none data-[highlighted]:bg-green9 data-[highlighted]:text-green1"
              :value="option"
            >
              <SelectItemIndicator class="absolute left-0 w-[25px] inline-flex items-center justify-center">
                <Icon icon="radix-icons:check" />
              </SelectItemIndicator>
              <SelectItemText>
                {{ option }}
              </SelectItemText>
            </SelectItem>
          </SelectGroup>
          <SelectSeparator class="h-[1px] bg-green6 m-[5px]" />
          <SelectLabel class="px-[25px] text-xs leading-[25px] text-mauve11">
            Vegetables
          </SelectLabel>
          <SelectGroup>
            <SelectItem
              v-for="(option, index) in vegetables"
              :key="index"
              class="text-[13px] leading-none text-grass11 rounded-[3px] flex items-center h-[25px] pr-[35px] pl-[25px] relative select-none data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none data-[highlighted]:outline-none data-[highlighted]:bg-green9 data-[highlighted]:text-green1"
              :value="option"
              :disabled="option === 'Courgette'"
            >
              <SelectItemIndicator class="absolute left-0 w-[25px] inline-flex items-center justify-center">
                <Icon icon="radix-icons:check" />
              </SelectItemIndicator>
              <SelectItemText>
                {{ option }}
              </SelectItemText>
            </SelectItem>
          </SelectGroup>
        </SelectViewport>

        <SelectScrollDownButton class="flex items-center justify-center h-[25px] bg-white text-violet11 cursor-default">
          <Icon icon="radix-icons:chevron-down" />
        </SelectScrollDownButton>
      </SelectContent>
    </SelectPortal>
  </SelectRoot>
</template>

特徴

  • 制御付きまたは制御なしで使用できます。
  • 2つのポジショニングモードを提供します。
  • アイテム、ラベル、アイテムのグループをサポートします。
  • フォーカスは完全に管理されています。
  • 完全なキーボードナビゲーション。
  • カスタムプレースホルダーをサポートします。
  • タイプアヘッドをサポートします。
  • 右から左への方向をサポートします。

インストール

コマンドラインからコンポーネントをインストールします。

sh
$ npm add radix-vue

構造

すべてのパーツをインポートして組み合わせます。

vue
<script setup lang="ts">
import {
  SelectContent,
  SelectGroup,
  SelectItem,
  SelectItemIndicator,
  SelectLabel,
  SelectPortal,
  SelectRoot,
  SelectScrollDownButton,
  SelectScrollUpButton,
  SelectSeparator,
  SelectTrigger,
  SelectValue,
  SelectViewport,
} from 'radix-vue'
</script>

<template>
  <SelectRoot>
    <SelectTrigger>
      <SelectValue />
      <SelectIcon />
    </SelectTrigger>

    <SelectPortal>
      <SelectContent>
        <SelectScrollUpButton />
        <SelectViewport>
          <SelectItem>
            <SelectItemText />
            <SelectItemIndicator />
          </SelectItem>
          <SelectGroup>
            <SelectLabel />
            <SelectItem>
              <SelectItemText />
              <SelectItemIndicator />
            </SelectItem>
          </SelectGroup>
          <SelectSeparator />
        </SelectViewport>
        <SelectScrollDownButton />
        <SelectArrow />
      </SelectContent>
    </SelectPortal>
  </SelectRoot>
</template>

APIリファレンス

ルート

セレクトのすべてのパーツが含まれます

プロパティデフォルト
autocomplete
string

ネイティブのhtml入力autocomplete属性。

defaultOpen
boolean

最初にレンダリングされたときのセレクトの開閉状態。開閉状態を制御する必要がない場合に使用します。

defaultValue
''
string

最初にレンダリングされたときのセレクトの値。セレクトの状態を制御する必要がない場合に使用します

dir
'ltr' | 'rtl'

該当する場合、コンボボックスの読み取り方向。
省略した場合、ConfigProviderからグローバルに継承するか、LTR(左から右)の読み取りモードを想定します。

disabled
boolean

trueの場合、ユーザーがセレクトを操作するのを防ぎます

modelValue
string

セレクトの制御された値。v-modelとしてバインドできます。

name
string

セレクトの名前。名前と値のペアの一部として、所有するフォームとともに送信されます。

open
boolean

セレクトの制御された開閉状態。v-model:openとしてバインドできます。

required
boolean

trueの場合、所有するフォームを送信する前に、ユーザーが値を選択する必要があることを示します。

イベントペイロード
update:modelValue
[value: string]

値が変更されたときに呼び出されるイベントハンドラー。

update:open
[value: boolean]

コンテキストメニューの開閉状態が変更されたときに呼び出されるイベントハンドラー。

スロット(デフォルト)ペイロード
modelValue
string

現在の入力値

open
boolean

現在の開閉状態

トリガー

セレクトを切り替えるボタン。SelectContentは、トリガー上に整列して配置されます。

プロパティデフォルト
as
'button'
AsTag | Component

このコンポーネントがレンダリングされる要素またはコンポーネント。asChildで上書きできます

asChild
boolean

子として渡された要素のデフォルトのレンダリング要素を変更し、それらのプロパティと動作をマージします。

詳細については、コンポジションガイドをお読みください。

disabled
boolean
データ属性
[data-state]"open" | "closed"
[data-disabled]無効の場合に存在します
[data-placeholder]プレースホルダーがある場合に存在します

選択された値を反映する部分。デフォルトでは、選択されたアイテムのテキストがレンダリングされます。より詳細な制御が必要な場合は、代わりにセレクトを制御し、独自のchildrenを渡すことができます。正しいポジショニングを確保するために、スタイルを設定しないでください。セレクトに値がない場合のために、オプションのplaceholderプロパティも使用できます。

プロパティデフォルト
as
'span'
AsTag | Component

このコンポーネントがレンダリングされる要素またはコンポーネント。asChildで上書きできます

asChild
boolean

子として渡された要素のデフォルトのレンダリング要素を変更し、それらのプロパティと動作をマージします。

詳細については、コンポジションガイドをお読みください。

placeholder
''
string

valueまたはdefaultValueが設定されていない場合にSelectValue内にレンダリングされるコンテンツ。

アイコン

開くことができるという事実を視覚的に示すためによく値の横に表示される小さなアイコン。デフォルトでは▼をレンダリングしますが、asChildまたはchildrenを使用して独自のアイコンを使用できます。

プロパティデフォルト
as
'div'
AsTag | Component

このコンポーネントがレンダリングされる要素またはコンポーネント。asChildで上書きできます

asChild
boolean

子として渡された要素のデフォルトのレンダリング要素を変更し、それらのプロパティと動作をマージします。

詳細については、コンポジションガイドをお読みください。

disabled
boolean

trueの場合、ユーザーがアイテムを操作するのを防ぎます。

textValue
string

タイプアヘッドの目的で使用されるオプションのテキスト。

デフォルトでは、タイプアヘッドの動作はSelectItemTextパーツの.textContentを使用します。

コンテンツが複雑な場合、または内部にテキスト以外のコンテンツがある場合は、これを使用してください。

value*
string

nameとともに送信されたときにデータとして与えられた値。

ポータル

使用すると、コンテンツ部分がbodyにポータルされます。

プロパティデフォルト
disabled
boolean

テレポーテーションを無効にして、コンポーネントをインラインでレンダリングします

reference

forceMount
boolean

より多くの制御が必要な場合に、強制的にマウントするために使用されます。Vueアニメーションライブラリでアニメーションを制御する場合に役立ちます。

to
string | HTMLElement

Vueネイティブのテレポーテーションコンポーネントのプロパティ:to

reference

コンテンツ

セレクトが開いているときにポップアップ表示されるコンポーネント。

プロパティデフォルト
align
'start' | 'center' | 'end'

トリガーに対する推奨される配置。衝突が発生すると変更される場合があります。

alignOffset
number

startまたはendの配置オプションからのピクセル単位のオフセット。

arrowPadding
number

矢印とコンテンツの端の間のパディング。コンテンツにborder-radiusがある場合、これにより角からはみ出さないようにします。

as
'div'
AsTag | Component

このコンポーネントがレンダリングされる要素またはコンポーネント。asChildで上書きできます

asChild
boolean

子として渡された要素のデフォルトのレンダリング要素を変更し、それらのプロパティと動作をマージします。

詳細については、コンポジションガイドをお読みください。

avoidCollisions
boolean

trueの場合、境界エッジとの衝突を防ぐために、サイドと整列の設定をオーバーライドします。

bodyLock
boolean

document.bodyがロックされ、スクロールが無効になります。

collisionBoundary
Element | (Element | null)[] | null

衝突境界として使用される要素。デフォルトではこれはビューポートですが、このチェックに含める追加の要素を指定できます。

collisionPadding
number | Partial<Record<'top' | 'right' | 'bottom' | 'left', number>>

衝突検出が発生する境界エッジからのピクセル単位の距離。数値(すべての辺で同じ)または部分的なパディングオブジェクト(例:{ top: 20, left: 20 })を受け入れます。

forceMount
boolean

より多くの制御が必要な場合に、強制的にマウントするために使用されます。Vueアニメーションライブラリでアニメーションを制御する場合に役立ちます。

hideWhenDetached
boolean

トリガーが完全に隠れたときにコンテンツを非表示にするかどうか。

position
'popper' | 'item-aligned'

使用する位置調整モード

item-aligned (デフォルト) - アクティブなアイテムを基準にコンテンツを配置することで、ネイティブのMacOSメニューと同様に動作します。
popper - PopoverDropdownMenu などの他のプリミティブと同じ方法でコンテンツを配置します。

prioritizePosition
boolean

コンテンツをビューポート内に強制的に配置します。

参照要素と重なる可能性があり、望ましくない場合があります。

side
'top' | 'right' | 'bottom' | 'left'

開いたときにレンダリングするトリガーの優先側。衝突が発生し、avoidCollisionsが有効になっている場合は反転されます。

sideOffset
number

トリガーからのピクセル単位の距離。

sticky
'partial' | 'always'

アライン軸での固定動作。partial は、トリガーが少なくとも部分的に境界内にある限りコンテンツを境界内に保持し、"always" はコンテンツを常に境界内に保持します。

updatePositionStrategy
'always' | 'optimized'

アニメーションフレームごとに浮動要素の位置を更新する戦略。

イベントペイロード
closeAutoFocus
[event: Event]

クローズ時に自動フォーカスされるときに呼び出されるイベントハンドラー。キャンセル可能です。

escapeKeyDown
[event: KeyboardEvent]

エスケープキーが押されたときに呼び出されるイベントハンドラー。キャンセル可能です。

pointerDownOutside
[event: PointerDownOutsideEvent]

DismissableLayer の外で pointerdown イベントが発生したときに呼び出されるイベントハンドラー。キャンセル可能です。

データ属性
[data-state]"open" | "closed"
[data-side]"left" | "right" | "bottom" | "top"
[data-align]"start" | "end" | "center"
CSS変数説明
--radix-select-content-transform-origin
コンテンツと矢印の位置/オフセットから計算された transform-originposition="popper" の場合にのみ存在します。
--radix-select-content-available-width
トリガーと境界エッジの間の残りの幅。position="popper" の場合にのみ存在します。
--radix-select-content-available-height
トリガーと境界エッジの間の残りの高さ。position="popper" の場合にのみ存在します。
--radix-select-trigger-width
トリガーの幅。position="popper" の場合にのみ存在します。
--radix-select-trigger-height
トリガーの高さ。position="popper" の場合にのみ存在します。

Viewport

すべてのアイテムを含むスクロールビューポート。

プロパティデフォルト
as
'div'
AsTag | Component

このコンポーネントがレンダリングされる要素またはコンポーネント。asChildで上書きできます

asChild
boolean

子として渡された要素のデフォルトのレンダリング要素を変更し、それらのプロパティと動作をマージします。

詳細については、コンポジションガイドをお読みください。

nonce
string

コンテンツセキュリティポリシーで使用できる nonce 属性をスタイルタグに追加します。
省略した場合、グローバルに ConfigProvider から継承します。

Item

選択アイテムを含むコンポーネント。

プロパティデフォルト
as
'div'
AsTag | Component

このコンポーネントがレンダリングされる要素またはコンポーネント。asChildで上書きできます

asChild
boolean

子として渡された要素のデフォルトのレンダリング要素を変更し、それらのプロパティと動作をマージします。

詳細については、コンポジションガイドをお読みください。

disabled
boolean

trueの場合、ユーザーがアイテムを操作するのを防ぎます。

textValue
string

タイプアヘッドの目的で使用されるオプションのテキスト。

デフォルトでは、タイプアヘッドの動作はSelectItemTextパーツの.textContentを使用します。

コンテンツが複雑な場合、または内部にテキスト以外のコンテンツがある場合は、これを使用してください。

value*
string

nameとともに送信されたときにデータとして与えられた値。

データ属性
[data-state]"checked" | "unchecked"
[data-highlighted]ハイライト時に存在します
[data-disabled]無効の場合に存在します

ItemText

アイテムのテキスト部分。そのアイテムが選択されたときにトリガーに表示したいテキストのみを含める必要があります。正しい配置を確保するためにスタイルを設定しないでください。

プロパティデフォルト
as
'span'
AsTag | Component

このコンポーネントがレンダリングされる要素またはコンポーネント。asChildで上書きできます

asChild
boolean

子として渡された要素のデフォルトのレンダリング要素を変更し、それらのプロパティと動作をマージします。

詳細については、コンポジションガイドをお読みください。

ItemIndicator

アイテムが選択されているときにレンダリングします。この要素に直接スタイルを設定することも、アイコンを入れるためのラッパーとして使用することも、両方行うこともできます。

プロパティデフォルト
as
'span'
AsTag | Component

このコンポーネントがレンダリングされる要素またはコンポーネント。asChildで上書きできます

asChild
boolean

子として渡された要素のデフォルトのレンダリング要素を変更し、それらのプロパティと動作をマージします。

詳細については、コンポジションガイドをお読みください。

ScrollUpButton

ビューポートのオーバーフローを表示し、上方向へのスクロールを機能的に有効にするためのアフォーダンスとして使用されるオプションのボタン。

プロパティデフォルト
as
'div'
AsTag | Component

このコンポーネントがレンダリングされる要素またはコンポーネント。asChildで上書きできます

asChild
boolean

子として渡された要素のデフォルトのレンダリング要素を変更し、それらのプロパティと動作をマージします。

詳細については、コンポジションガイドをお読みください。

ScrollDownButton

ビューポートのオーバーフローを表示し、下方向へのスクロールを機能的に有効にするためのアフォーダンスとして使用されるオプションのボタン。

プロパティデフォルト
as
'div'
AsTag | Component

このコンポーネントがレンダリングされる要素またはコンポーネント。asChildで上書きできます

asChild
boolean

子として渡された要素のデフォルトのレンダリング要素を変更し、それらのプロパティと動作をマージします。

詳細については、コンポジションガイドをお読みください。

Group

複数のアイテムをグループ化するために使用します。自動ラベリングによって優れたアクセシビリティを確保するために SelectLabel と組み合わせて使用します。

プロパティデフォルト
as
'div'
AsTag | Component

このコンポーネントがレンダリングされる要素またはコンポーネント。asChildで上書きできます

asChild
boolean

子として渡された要素のデフォルトのレンダリング要素を変更し、それらのプロパティと動作をマージします。

詳細については、コンポジションガイドをお読みください。

Label

グループのラベルをレンダリングするために使用します。矢印キーを使用してフォーカスすることはできません。

プロパティデフォルト
as
'div'
AsTag | Component

このコンポーネントがレンダリングされる要素またはコンポーネント。asChildで上書きできます

asChild
boolean

子として渡された要素のデフォルトのレンダリング要素を変更し、それらのプロパティと動作をマージします。

詳細については、コンポジションガイドをお読みください。

for
string

Separator

Select内のアイテムを視覚的に区切るために使用します

プロパティデフォルト
as
'div'
AsTag | Component

このコンポーネントがレンダリングされる要素またはコンポーネント。asChildで上書きできます

asChild
boolean

子として渡された要素のデフォルトのレンダリング要素を変更し、それらのプロパティと動作をマージします。

詳細については、コンポジションガイドをお読みください。

Arrow

コンテンツと一緒にレンダリングするオプションの矢印要素。これは、トリガーと SelectContent を視覚的にリンクするのに役立ちます。SelectContent 内でレンダリングする必要があります。positionpopper に設定されている場合にのみ使用できます。

プロパティデフォルト
as
'svg'
AsTag | Component

このコンポーネントがレンダリングされる要素またはコンポーネント。asChildで上書きできます

asChild
boolean

子として渡された要素のデフォルトのレンダリング要素を変更し、それらのプロパティと動作をマージします。

詳細については、コンポジションガイドをお読みください。

height
5
number

ピクセル単位の矢印の高さ。

width
10
number

ピクセル単位の矢印の幅。

Examples

Change the positioning mode

デフォルトでは、Select は、アクティブなアイテムを基準に SelectContent を配置することで、ネイティブのMacOSメニューと同様に動作します。Popover または DropdownMenu と同様の代替の配置方法を優先する場合は、positionpopper に設定し、sidesideOffset などの追加の配置オプションを使用できます。

vue
// index.vue
<script setup lang="ts">
import {
  SelectContent,
  SelectGroup,
  SelectItem,
  SelectItemIndicator,
  SelectLabel,
  SelectPortal,
  SelectRoot,
  SelectSeparator,
  SelectTrigger,
} from 'radix-vue'
</script>

<template>
  <SelectRoot>
    <SelectTrigger></SelectTrigger>
    <SelectPortal>
      <SelectContent
        position="popper"
        :side-offset="5"
      >

      </SelectContent>
    </SelectPortal>
  </SelectRoot>
</template>

Constrain the content size

SelectContentposition="popper" を使用する場合、コンテンツの幅をトリガーの幅に一致するように制約したい場合があります。また、高さをビューポートを超えないように制約することもできます。

これをサポートするために、--radix-select-trigger-width--radix-select-content-available-height など、いくつかのCSSカスタムプロパティを公開しています。コンテンツのサイズを制約するために使用します。

vue
// index.vue
<script setup lang="ts">
import {
  SelectContent,
  SelectGroup,
  SelectItem,
  SelectItemIndicator,
  SelectLabel,
  SelectPortal,
  SelectRoot,
  SelectSeparator,
  SelectTrigger,
} from 'radix-vue'
</script>

<template>
  <SelectRoot>
    <SelectTrigger></SelectTrigger>
    <SelectPortal>
      <SelectContent
        class="SelectContent"
        position="popper"
        :side-offset="5"
      >

      </SelectContent>
    </SelectPortal>
  </SelectRoot>
</template>
css
/* styles.css */
.SelectContent {
  width: var(--radix-select-trigger-width);
  max-height: var(--radix-select-content-available-height);
}

With disabled items

data-disabled 属性を使用して、無効なアイテムに特別なスタイルを追加できます。

vue
// index.vue
<script setup lang="ts">
import {
  SelectContent,
  SelectGroup,
  SelectItem,
  SelectItemIndicator,
  SelectLabel,
  SelectPortal,
  SelectRoot,
  SelectSeparator,
  SelectTrigger,
} from 'radix-vue'
</script>

<template>
  <SelectRoot>
    <SelectTrigger></SelectTrigger>
    <SelectPortal>
      <SelectContent>
        <SelectViewport>
          <SelectItem
            class="SelectItem"
            disabled
          >

          </SelectItem>
          <SelectItem></SelectItem>
          <SelectItem></SelectItem>
        </SelectViewport>
      </SelectContent>
    </SelectPortal>
  </SelectRoot>
</template>
css
/* styles.css */
.SelectItem[data-disabled] {
  color: "gainsboro";
}

With a placeholder

selectに値がない場合は、Valueplaceholder プロパティを使用できます。スタイリングに役立つ Triggerdata-placeholder 属性もあります。

vue
// index.vue
<script setup lang="ts">
import {
  SelectContent,
  SelectGroup,
  SelectItem,
  SelectItemIndicator,
  SelectLabel,
  SelectPortal,
  SelectRoot,
  SelectSeparator,
  SelectTrigger,
} from 'radix-vue'
import './styles.css'
</script>

<template>
  <SelectRoot>
    <SelectTrigger class="SelectTrigger">
      <SelectValue placeholder="Pick an option" />
      <SelectIcon />
    </SelectTrigger>
    <SelectPortal>
      <SelectContent></SelectContent>
    </SelectPortal>
  </SelectRoot>
</template>
css
/* styles.css */
.SelectTrigger[data-placeholder] {
  color: "gainsboro";
}

With separators

アイテム間に区切りを追加するには、Separator パーツを使用します。

vue
<template>
  <SelectRoot>
    <SelectTrigger></SelectTrigger>
    <SelectPortal>
      <SelectContent>
        <SelectViewport>
          <SelectItem></SelectItem>
          <SelectItem></SelectItem>
          <SelectItem></SelectItem>
          <SelectSeparator />
          <SelectItem></SelectItem>
          <SelectItem></SelectItem>
        </SelectViewport>
      </SelectContent>
    </SelectPortal>
  </SelectRoot>
</template>

With grouped items

セクション内のアイテムをグループ化するには、Group および Label パーツを使用します。

vue
<template>
  <SelectRoot>
    <SelectTrigger></SelectTrigger>
    <SelectPortal>
      <SelectContent>
        <SelectViewport>
          <SelectGroup>
            <SelectLabel>Label</SelectLabel>
            <SelectItem></SelectItem>
            <SelectItem></SelectItem>
            <SelectItem></SelectItem>
          </SelectGroup>
        </SelectViewport>
      </SelectContent>
    </SelectPortal>
  </SelectRoot>
</template>

With complex items

アイテムでカスタムコンテンツを使用できます。

vue
<script setup lang="ts">
import {
  SelectContent,
  SelectGroup,
  SelectItem,
  SelectItemIndicator,
  SelectLabel,
  SelectPortal,
  SelectRoot,
  SelectSeparator,
  SelectTrigger,
} from 'radix-vue'
</script>

<template>
  <SelectRoot>
    <SelectTrigger></SelectTrigger>
    <SelectPortal>
      <SelectContent>
        <SelectViewport>
          <SelectItem>
            <SelectItemText>
              <img src="">
              Adolfo Hess
            </SelectItemText>
            <SelectItemIndicator></SelectItemIndicator>
          </SelectItem>
          <SelectItem></SelectItem> <SelectItem></SelectItem>
        </SelectViewport>
      </SelectContent>
    </SelectPortal>
  </SelectRoot>
</template>

Controlling the value displayed in the trigger

デフォルトでは、トリガーには選択されたアイテムの ItemText のコンテンツが自動的に表示されます。ItemText パーツの内側/外側に配置するものを選択することで、表示されるものを制御できます。

より柔軟性が必要な場合は、v-model プロパティを使用してコンポーネントを制御し、slotSelectValue に渡すことができます。そこに配置するものがアクセス可能であることを確認してください。

vue
<script setup>
const countries = { 'france': '🇫🇷', 'united-kingdom': '🇬🇧', 'spain': '🇪🇸' }

const value = ref('france')
</script>

<template>
  <SelectRoot v-model="value">
    <SelectTrigger>
      <SelectValue aria-label="value">
        {{ countries[value] }}
      </SelectValue>
      <SelectIcon />
    </SelectTrigger>
    <SelectPortal>
      <SelectContent>
        <SelectViewport>
          <SelectItem value="france">
            <SelectItemText>France</SelectItemText>
            <SelectItemIndicator></SelectItemIndicator>
          </SelectItem>
          <SelectItem value="united-kingdom">
            <SelectItemText>United Kingdom</SelectItemText>
            <SelectItemIndicator></SelectItemIndicator>
          </SelectItem>
          <SelectItem value="spain">
            <SelectItemText>Spain</SelectItemText>
            <SelectItemIndicator></SelectItemIndicator>
          </SelectItem>
        </SelectViewport>
      </SelectContent>
    </SelectPortal>
  </SelectRoot>
</template>

With custom scrollbar

最適なUXのために ScrollUpButton および ScrollDownButton パーツを使用することをお勧めするため、ネイティブのスクロールバーはデフォルトで非表示になっています。これらのパーツを使用したくない場合は、Scroll Area プリミティブを使用して select を構成します。

vue
// index.vue
<script setup lang="ts">
import {
  ScrollAreaRoot,
  ScrollAreaScrollbar,
  ScrollAreaThumb,
  ScrollAreaViewport,
  SelectContent,
  SelectGroup,
  SelectItem,
  SelectItemIndicator,
  SelectLabel,
  SelectPortal,
  SelectRoot,
  SelectSeparator,
  SelectTrigger,
} from 'radix-vue'
</script>

<template>
  <SelectRoot>
    <SelectTrigger></SelectTrigger>
    <SelectPortal>
      <SelectContent>
        <ScrollAreaRoot
          class="ScrollAreaRoot"
          type="auto"
        >
          <SelectViewport as-child>
            <ScrollAreaViewport class="ScrollAreaViewport">
              <StyledItem></StyledItem> <StyledItem></StyledItem>
              <StyledItem></StyledItem>
            </ScrollAreaViewport>
          </SelectViewport>
          <ScrollAreaScrollbar
            class="ScrollAreaScrollbar"
            orientation="vertical"
          >
            <ScrollAreaThumb class="ScrollAreaThumb" />
          </ScrollAreaScrollbar>
        </ScrollAreaRoot>
      </SelectContent>
    </SelectPortal>
  </SelectRoot>
</template>
css
/* styles.css */
.ScrollAreaRoot {
  width: 100%;
  height: 100%;
}

.ScrollAreaViewport {
  width: 100%;
  height: 100%;
}

.ScrollAreaScrollbar {
  width: 4px;
  padding: 5px 2px;
}

.ScrollAreaThumb {
  background: rgba(0, 0, 0, 0.3);
  borderradius: 3px;
}

Accessibility

ListBox WAI-ARIA デザインパターンに準拠しています。

詳細については、W3C Select-Only Combobox の例を参照してください。

Keyboard Interactions

キー説明
スペース
フォーカスが SelectTrigger にある場合、select を開き、選択されたアイテムにフォーカスを合わせます。
フォーカスがアイテムにある場合、フォーカスされたアイテムを選択します。
Enter
フォーカスが SelectTrigger にある場合、select を開き、最初のアイテムにフォーカスを合わせます。
フォーカスがアイテムにある場合、フォーカスされたアイテムを選択します。
ArrowDown
フォーカスが SelectTrigger にある場合、Select を開きます
フォーカスがアイテムにある場合、フォーカスを次のアイテムに移動します。
ArrowUp
フォーカスが SelectTrigger にある場合、Select を開きます
フォーカスがアイテムにある場合、フォーカスを前のアイテムに移動します。
Esc
select を閉じ、フォーカスを SelectTrigger に移動します。

Labelling

Select の視覚的でアクセス可能なラベルを提供するには、Label コンポーネントを使用します

vue
<script setup lang="ts">
import { Icon } from '@iconify/vue'
import { ref } from 'vue'
import {
  Label,
  SelectContent,
  SelectGroup,
  SelectItem,
  SelectItemIndicator,
  SelectLabel,
  SelectPortal,
  SelectRoot,
  SelectSeparator,
  SelectTrigger,
} from 'radix-vue'
</script>

<template>
  <Label>
    Country
    <SelectRoot></SelectRoot>
  </Label>

  <!-- or -->

  <Label for="country">Country</Label>
  <SelectRoot>
    <SelectTrigger id="country">

    </SelectTrigger>
    <SelectPortal>
      <SelectContent></SelectContent>
    </SelectPortal>
  </SelectRoot>
</template>

Custom APIs

プリミティブパーツを独自のコンポーネントに抽象化することで、独自のAPIを作成します。

Abstract down to Select and SelectItem

この例では、ほとんどのパーツを抽象化しています。

Usage

vue
<script setup lang="ts">
import { Select, SelectItem } from './your-select'
</script>

<template>
  <Select default-value="2">
    <SelectItem value="1">
      Item 1
    </SelectItem>
    <SelectItem value="2">
      Item 2
    </SelectItem>
    <SelectItem value="3">
      Item 3
    </SelectItem>
  </Select>
</template>

Implementation

ts
// your-select.ts
export { default as Select } from 'Select.vue'
export { default as SelectItem } from 'SelectItem.vue'
vue
<!-- Select.vue -->
<script setup lang="ts">
import { CheckIcon, ChevronDownIcon, ChevronUpIcon, } from '@radix-icons/vue'
import { SelectContent, SelectIcon, SelectPortal, SelectRoot, SelectScrollDownButton, SelectScrollUpButton, SelectTrigger, SelectValue, SelectViewport, useForwardPropsEmits } from 'radix-vue'
import type { SelectRootEmits, SelectRootProps } from 'radix-vue'

const props = defineProps<SelectRootProps>()
const emits = defineEmits<SelectRootEmits>()

const forward = useForwardPropsEmits(props, emits)
</script>

<template>
  <SelectRoot v-bind="forward">
    <SelectTrigger>
      <SelectValue />
      <SelectIcon>
        <ChevronDownIcon />
      </SelectIcon>
    </SelectTrigger>

    <SelectPortal>
      <SelectContent>
        <SelectScrollUpButton>
          <ChevronUpIcon />
        </SelectScrollUpButton>
        <SelectViewport>
          <slot />
        </SelectViewport>
        <SelectScrollDownButton>
          <ChevronDownIcon />
        </SelectScrollDownButton>
      </SelectContent>
    </SelectPortal>
  </SelectRoot>
</template>
vue
<!-- SelectItem.vue -->
<script setup lang="ts">
import { CheckIcon } from '@radix-icons/vue'
import { SelectItem, SelectItemIndicator, type SelectItemProps, SelectItemText } from 'radix-vue'

const props = defineProps<SelectItemProps>()
</script>

<template>
  <SelectItem v-bind="props">
    <SelectItemText>
      <slot />
    </SelectItemText>
    <SelectItemIndicator>
      <CheckIcon />
    </SelectItemIndicator>
  </SelectItem>
</template>