---
title: Select
description: Dropdown select for choosing from a list of options.
icon: square-caret-down
---

import { ComponentPreview } from "/snippets/component-preview.mdx";

Select dropdowns let users pick one option from a collapsible list. The selected option's `value` string is stored in client state, accessible via `.rx`.

## Basic Usage

A `Select` is a container — use the `with` block to add `SelectOption` children. Each option needs a `value` (what gets stored) and a `label` (what the user sees):

<ComponentPreview json={{"view":{"name":"select_2","type":"Select","placeholder":"Choose size...","size":"default","disabled":false,"required":false,"children":[{"type":"SelectOption","value":"sm","label":"Small","selected":false,"disabled":false},{"type":"SelectOption","value":"md","label":"Medium","selected":false,"disabled":false},{"type":"SelectOption","value":"lg","label":"Large","selected":false,"disabled":false}]}}} playground="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgU2VsZWN0LCBTZWxlY3RPcHRpb24KCndpdGggU2VsZWN0KHBsYWNlaG9sZGVyPSJDaG9vc2Ugc2l6ZS4uLiIpOgogICAgU2VsZWN0T3B0aW9uKHZhbHVlPSJzbSIsIGxhYmVsPSJTbWFsbCIpCiAgICBTZWxlY3RPcHRpb24odmFsdWU9Im1kIiwgbGFiZWw9Ik1lZGl1bSIpCiAgICBTZWxlY3RPcHRpb24odmFsdWU9ImxnIiwgbGFiZWw9IkxhcmdlIikK">
<CodeGroup>
```python Python icon="python"
from prefab_ui.components import Select, SelectOption

with Select(placeholder="Choose size..."):
    SelectOption(value="sm", label="Small")
    SelectOption(value="md", label="Medium")
    SelectOption(value="lg", label="Large")
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "name": "select_2",
    "type": "Select",
    "placeholder": "Choose size...",
    "size": "default",
    "disabled": false,
    "required": false,
    "children": [
      {
        "type": "SelectOption",
        "value": "sm",
        "label": "Small",
        "selected": false,
        "disabled": false
      },
      {
        "type": "SelectOption",
        "value": "md",
        "label": "Medium",
        "selected": false,
        "disabled": false
      },
      {
        "type": "SelectOption",
        "value": "lg",
        "label": "Large",
        "selected": false,
        "disabled": false
      }
    ]
  }
}
```
</CodeGroup>
</ComponentPreview>

## Pre-selected Option

Mark an option as `selected=True` to have it chosen when the component first renders:

<ComponentPreview json={{"view":{"name":"select_3","type":"Select","placeholder":"Select country","size":"default","disabled":false,"required":false,"children":[{"type":"SelectOption","value":"us","label":"United States","selected":false,"disabled":false},{"type":"SelectOption","value":"uk","label":"United Kingdom","selected":true,"disabled":false},{"type":"SelectOption","value":"ca","label":"Canada","selected":false,"disabled":false}]}}} playground="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgU2VsZWN0LCBTZWxlY3RPcHRpb24KCndpdGggU2VsZWN0KHBsYWNlaG9sZGVyPSJTZWxlY3QgY291bnRyeSIpOgogICAgU2VsZWN0T3B0aW9uKHZhbHVlPSJ1cyIsIGxhYmVsPSJVbml0ZWQgU3RhdGVzIikKICAgIFNlbGVjdE9wdGlvbih2YWx1ZT0idWsiLCBsYWJlbD0iVW5pdGVkIEtpbmdkb20iLCBzZWxlY3RlZD1UcnVlKQogICAgU2VsZWN0T3B0aW9uKHZhbHVlPSJjYSIsIGxhYmVsPSJDYW5hZGEiKQo=">
<CodeGroup>
```python Python icon="python"
from prefab_ui.components import Select, SelectOption

with Select(placeholder="Select country"):
    SelectOption(value="us", label="United States")
    SelectOption(value="uk", label="United Kingdom", selected=True)
    SelectOption(value="ca", label="Canada")
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "name": "select_3",
    "type": "Select",
    "placeholder": "Select country",
    "size": "default",
    "disabled": false,
    "required": false,
    "children": [
      {
        "type": "SelectOption",
        "value": "us",
        "label": "United States",
        "selected": false,
        "disabled": false
      },
      {
        "type": "SelectOption",
        "value": "uk",
        "label": "United Kingdom",
        "selected": true,
        "disabled": false
      },
      {
        "type": "SelectOption",
        "value": "ca",
        "label": "Canada",
        "selected": false,
        "disabled": false
      }
    ]
  }
}
```
</CodeGroup>
</ComponentPreview>

## Sizes

Selects come in two sizes. The `"sm"` variant is useful when space is tight or when embedding a select alongside other compact controls:

<ComponentPreview json={{"view":{"cssClass":"gap-4","type":"Column","children":[{"name":"select_4","type":"Select","placeholder":"Default size","size":"default","disabled":false,"required":false,"children":[{"type":"SelectOption","value":"1","label":"Option 1","selected":false,"disabled":false},{"type":"SelectOption","value":"2","label":"Option 2","selected":false,"disabled":false}]},{"name":"select_5","type":"Select","placeholder":"Small size","size":"sm","disabled":false,"required":false,"children":[{"type":"SelectOption","value":"1","label":"Option 1","selected":false,"disabled":false},{"type":"SelectOption","value":"2","label":"Option 2","selected":false,"disabled":false}]}]}}} playground=" ">
<CodeGroup>
```python Python icon="python"
from prefab_ui.components import Column, Select, SelectOption

with Column(gap=4):
    with Select(placeholder="Default size"):
        SelectOption(value="1", label="Option 1")
        SelectOption(value="2", label="Option 2")

    with Select(placeholder="Small size", size="sm"):
        SelectOption(value="1", label="Option 1")
        SelectOption(value="2", label="Option 2")
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "cssClass": "gap-4",
    "type": "Column",
    "children": [
      {
        "name": "select_4",
        "type": "Select",
        "placeholder": "Default size",
        "size": "default",
        "disabled": false,
        "required": false,
        "children": [
          {
            "type": "SelectOption",
            "value": "1",
            "label": "Option 1",
            "selected": false,
            "disabled": false
          },
          {
            "type": "SelectOption",
            "value": "2",
            "label": "Option 2",
            "selected": false,
            "disabled": false
          }
        ]
      },
      {
        "name": "select_5",
        "type": "Select",
        "placeholder": "Small size",
        "size": "sm",
        "disabled": false,
        "required": false,
        "children": [
          {
            "type": "SelectOption",
            "value": "1",
            "label": "Option 1",
            "selected": false,
            "disabled": false
          },
          {
            "type": "SelectOption",
            "value": "2",
            "label": "Option 2",
            "selected": false,
            "disabled": false
          }
        ]
      }
    ]
  }
}
```
</CodeGroup>
</ComponentPreview>

## With Label

Pair a `Select` with a `Label` in a `Column` for a standard form field pattern:

<ComponentPreview json={{"view":{"cssClass":"gap-2","type":"Column","children":[{"type":"Label","text":"Preferred language"},{"name":"select_6","type":"Select","placeholder":"Choose language","size":"default","disabled":false,"required":false,"children":[{"type":"SelectOption","value":"en","label":"English","selected":false,"disabled":false},{"type":"SelectOption","value":"es","label":"Spanish","selected":false,"disabled":false},{"type":"SelectOption","value":"fr","label":"French","selected":false,"disabled":false}]}]}}} playground="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgQ29sdW1uLCBMYWJlbCwgU2VsZWN0LCBTZWxlY3RPcHRpb24KCndpdGggQ29sdW1uKGdhcD0yKToKICAgIExhYmVsKCJQcmVmZXJyZWQgbGFuZ3VhZ2UiKQogICAgd2l0aCBTZWxlY3QocGxhY2Vob2xkZXI9IkNob29zZSBsYW5ndWFnZSIpOgogICAgICAgIFNlbGVjdE9wdGlvbih2YWx1ZT0iZW4iLCBsYWJlbD0iRW5nbGlzaCIpCiAgICAgICAgU2VsZWN0T3B0aW9uKHZhbHVlPSJlcyIsIGxhYmVsPSJTcGFuaXNoIikKICAgICAgICBTZWxlY3RPcHRpb24odmFsdWU9ImZyIiwgbGFiZWw9IkZyZW5jaCIpCg==">
<CodeGroup>
```python Python icon="python"
from prefab_ui.components import Column, Label, Select, SelectOption

with Column(gap=2):
    Label("Preferred language")
    with Select(placeholder="Choose language"):
        SelectOption(value="en", label="English")
        SelectOption(value="es", label="Spanish")
        SelectOption(value="fr", label="French")
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "cssClass": "gap-2",
    "type": "Column",
    "children": [
      {"type": "Label", "text": "Preferred language"},
      {
        "name": "select_6",
        "type": "Select",
        "placeholder": "Choose language",
        "size": "default",
        "disabled": false,
        "required": false,
        "children": [
          {
            "type": "SelectOption",
            "value": "en",
            "label": "English",
            "selected": false,
            "disabled": false
          },
          {
            "type": "SelectOption",
            "value": "es",
            "label": "Spanish",
            "selected": false,
            "disabled": false
          },
          {
            "type": "SelectOption",
            "value": "fr",
            "label": "French",
            "selected": false,
            "disabled": false
          }
        ]
      }
    ]
  }
}
```
</CodeGroup>
</ComponentPreview>

## Reading the Value

Use `.rx` to get a reactive reference to the selected option's `value` string. When the user picks an option, anything bound to `.rx` updates automatically:

<ComponentPreview json={{"view":{"cssClass":"gap-4","type":"Column","children":[{"name":"select_7","type":"Select","placeholder":"Choose a planet...","size":"default","disabled":false,"required":false,"children":[{"type":"SelectOption","value":"magrathea","label":"Magrathea","selected":false,"disabled":false},{"type":"SelectOption","value":"betelgeuse","label":"Betelgeuse V","selected":false,"disabled":false},{"type":"SelectOption","value":"vogsphere","label":"Vogsphere","selected":false,"disabled":false},{"type":"SelectOption","value":"earth","label":"Earth (Mostly Harmless)","selected":false,"disabled":false}]},{"content":"You chose: {{ select_7 }}","type":"Text"}]}}} playground=" ">
<CodeGroup>
```python Python icon="python"
from prefab_ui.components import Column, Select, SelectOption, Text

with Column(gap=4):
    with Select(placeholder="Choose a planet...") as sel:
        SelectOption(value="magrathea", label="Magrathea")
        SelectOption(value="betelgeuse", label="Betelgeuse V")
        SelectOption(value="vogsphere", label="Vogsphere")
        SelectOption(value="earth", label="Earth (Mostly Harmless)")
    Text(f"You chose: {sel.rx}")
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "cssClass": "gap-4",
    "type": "Column",
    "children": [
      {
        "name": "select_7",
        "type": "Select",
        "placeholder": "Choose a planet...",
        "size": "default",
        "disabled": false,
        "required": false,
        "children": [
          {
            "type": "SelectOption",
            "value": "magrathea",
            "label": "Magrathea",
            "selected": false,
            "disabled": false
          },
          {
            "type": "SelectOption",
            "value": "betelgeuse",
            "label": "Betelgeuse V",
            "selected": false,
            "disabled": false
          },
          {
            "type": "SelectOption",
            "value": "vogsphere",
            "label": "Vogsphere",
            "selected": false,
            "disabled": false
          },
          {
            "type": "SelectOption",
            "value": "earth",
            "label": "Earth (Mostly Harmless)",
            "selected": false,
            "disabled": false
          }
        ]
      },
      {"content": "You chose: {{ select_7 }}", "type": "Text"}
    ]
  }
}
```
</CodeGroup>
</ComponentPreview>

Pick an option and the text updates instantly. The `.rx` reference holds the `value` string of whichever option is selected — `"magrathea"`, `"betelgeuse"`, etc. — not the display label.

## Actions

The `on_change` parameter fires actions when the selection changes. Inside the action, `$event` holds the newly selected `value` string:

<ComponentPreview json={{"view":{"cssClass":"gap-4","type":"Column","children":[{"name":"select_8","type":"Select","placeholder":"Pick a color...","size":"default","disabled":false,"required":false,"onChange":{"action":"setState","key":"picked","value":"You chose: {{ $event }}"},"children":[{"type":"SelectOption","value":"red","label":"Red","selected":false,"disabled":false},{"type":"SelectOption","value":"green","label":"Green","selected":false,"disabled":false},{"type":"SelectOption","value":"blue","label":"Blue","selected":false,"disabled":false}]},{"cssClass":"text-muted-foreground","content":"{{ picked | default:'Make a selection' }}","type":"Text"}]}}} playground=" ">
<CodeGroup>
```python Python icon="python"
from prefab_ui.components import Column, Select, SelectOption, Text
from prefab_ui.actions import SetState

with Column(gap=4):
    with Select(
        placeholder="Pick a color...",
        on_change=SetState("picked", "You chose: {{ $event }}"),
    ):
        SelectOption(value="red", label="Red")
        SelectOption(value="green", label="Green")
        SelectOption(value="blue", label="Blue")
    Text(
        "{{ picked | default:'Make a selection' }}",
        css_class="text-muted-foreground",
    )
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "cssClass": "gap-4",
    "type": "Column",
    "children": [
      {
        "name": "select_8",
        "type": "Select",
        "placeholder": "Pick a color...",
        "size": "default",
        "disabled": false,
        "required": false,
        "onChange": {"action": "setState", "key": "picked", "value": "You chose: {{ $event }}"},
        "children": [
          {
            "type": "SelectOption",
            "value": "red",
            "label": "Red",
            "selected": false,
            "disabled": false
          },
          {
            "type": "SelectOption",
            "value": "green",
            "label": "Green",
            "selected": false,
            "disabled": false
          },
          {
            "type": "SelectOption",
            "value": "blue",
            "label": "Blue",
            "selected": false,
            "disabled": false
          }
        ]
      },
      {
        "cssClass": "text-muted-foreground",
        "content": "{{ picked | default:'Make a selection' }}",
        "type": "Text"
      }
    ]
  }
}
```
</CodeGroup>
</ComponentPreview>

This is different from `.rx` — here we're transforming the value before storing it (prepending "You chose: "). For simple "show the current selection" cases, `.rx` is the better approach.

## API Reference

<Card icon="code" title="Select Parameters">
<ParamField body="placeholder" type="str | None" default="None">
  Placeholder text shown when no option is selected.
</ParamField>

<ParamField body="name" type="str | None" default="None">
  State key for the selected value. Auto-generated if not provided.
</ParamField>

<ParamField body="size" type="str" default="default">
  Select size: `"default"`, `"sm"`.
</ParamField>

<ParamField body="disabled" type="bool" default="False">
  Whether the select is non-interactive.
</ParamField>

<ParamField body="required" type="bool" default="False">
  Whether a selection is required for form submission.
</ParamField>

<ParamField body="on_change" type="Action | list[Action] | None" default="None">
  Action(s) to execute when the selection changes. `$event` is the `value` string of the selected option.
</ParamField>

<ParamField body="css_class" type="str | None" default="None">
  Additional Tailwind CSS classes.
</ParamField>
</Card>

<Card icon="code" title="SelectOption Parameters">
<ParamField body="value" type="str" required>
  The value stored in state when this option is selected.
</ParamField>

<ParamField body="label" type="str" required>
  Display text shown to the user.
</ParamField>

<ParamField body="selected" type="bool" default="False">
  Whether this option is initially selected.
</ParamField>

<ParamField body="disabled" type="bool" default="False">
  Whether this option is non-interactive.
</ParamField>

<ParamField body="css_class" type="str | None" default="None">
  Additional Tailwind CSS classes.
</ParamField>
</Card>

## Protocol Reference

```json Select
{
  "type": "Select",
  "children?": "[Component]",
  "let?": "object",
  "name?": "string",
  "placeholder?": "string",
  "size?": "sm | default",
  "disabled?": false,
  "required?": false,
  "onChange?": "Action | Action[]",
  "cssClass?": "string"
}
```

```json SelectOption
{
  "type": "SelectOption",
  "value": "string (required)",
  "label": "string (required)",
  "selected?": false,
  "disabled?": false,
  "cssClass?": "string"
}
```

For the complete protocol schema, see [Select](/protocol/select), [SelectOption](/protocol/select-option).
