> ## Documentation Index
> Fetch the complete documentation index at: https://prefab.prefect.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Select

> Dropdown select for choosing from a list of options.

export const ComponentPreview = ({json, height, resizable, bare, hideJson, playground, children}) => {
  const hostRef = React.useRef(null);
  const handleRef = React.useRef(null);
  const cardRef = React.useRef(null);
  const containerRef = React.useRef(null);
  const [previewWidth, setPreviewWidth] = React.useState(null);
  const [isDragging, setIsDragging] = React.useState(false);
  const [playgroundHref, setPlaygroundHref] = React.useState(null);
  React.useEffect(function () {
    if (!playground) return;
    var isLocal = location.hostname === "localhost" || location.hostname === "127.0.0.1";
    var path = isLocal ? "/playground" : "/docs/playground";
    var url = new URL(path, window.location.href);
    url.hash = "code=" + playground;
    setPlaygroundHref(url.href);
  }, [playground]);
  var jsonStr = typeof json === "string" ? json : JSON.stringify(json, null, 2);
  React.useEffect(function () {
    if (cardRef.current) {
      var card = cardRef.current.closest(".group");
      if (card) card.classList.remove("group");
    }
    var host = hostRef.current;
    if (!host || !json) return;
    function mount() {
      if (!window.__prefab || !host) return;
      var dark = document.documentElement.classList.contains("dark");
      handleRef.current = window.__prefab.mountPreview(host, jsonStr, {
        dark: dark
      });
      if (bare && host.shadowRoot) {
        var m = host.shadowRoot.querySelector("[data-prefab-mount]");
        if (m) m.style.background = "transparent";
      }
    }
    if (window.__prefab) {
      mount();
    } else {
      if (!window.__prefabLoading) {
        if (!window.__prefabReady) {
          var s = document.createElement("script");
          s.src = "/renderer.js";
          document.head.appendChild(s);
        }
        window.__prefabLoading = new Promise(function (resolve) {
          function check() {
            if (window.__prefabReady) {
              window.__prefabReady.then(resolve);
            } else {
              setTimeout(check, 10);
            }
          }
          check();
        });
      }
      window.__prefabLoading.then(mount);
    }
    var observer = new MutationObserver(function () {
      var dark = document.documentElement.classList.contains("dark");
      if (handleRef.current) handleRef.current.setDark(dark);
    });
    observer.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ["class"]
    });
    return function () {
      observer.disconnect();
      if (handleRef.current) {
        handleRef.current.unmount();
        handleRef.current = null;
      }
    };
  }, [json]);
  function startResize(e) {
    e.preventDefault();
    var startX = e.clientX;
    var startW = hostRef.current ? hostRef.current.offsetWidth : 0;
    var maxW = containerRef.current ? containerRef.current.offsetWidth - 10 : startW;
    setIsDragging(true);
    function onMove(ev) {
      var w = Math.max(260, Math.min(startW + (ev.clientX - startX), maxW));
      setPreviewWidth(w);
    }
    function onUp() {
      document.removeEventListener("mousemove", onMove);
      document.removeEventListener("mouseup", onUp);
      setIsDragging(false);
    }
    document.addEventListener("mousemove", onMove);
    document.addEventListener("mouseup", onUp);
  }
  if (bare) {
    return <div ref={hostRef} />;
  }
  if (resizable) {
    return <Card>
        <div ref={cardRef} />
        <div ref={containerRef} style={{
      display: "flex",
      position: "relative",
      overflow: "hidden"
    }}>
          <div ref={hostRef} style={{
      flex: previewWidth ? "none" : 1,
      width: previewWidth ? previewWidth + "px" : undefined,
      minWidth: 0
    }} />
          <div onMouseDown={startResize} style={{
      width: "14px",
      flexShrink: 0,
      cursor: "col-resize",
      background: isDragging ? "var(--border, #e5e7eb)" : "color-mix(in srgb, var(--border, #e5e7eb) 40%, transparent)",
      display: "flex",
      alignItems: "center",
      justifyContent: "center",
      transition: "background 0.15s",
      userSelect: "none"
    }}>
            <svg width="6" height="24" style={{
      opacity: 0.5
    }}>
              <circle cx="2" cy="4" r="1.2" fill="currentColor" />
              <circle cx="2" cy="9" r="1.2" fill="currentColor" />
              <circle cx="2" cy="14" r="1.2" fill="currentColor" />
              <circle cx="2" cy="19" r="1.2" fill="currentColor" />
              <circle cx="5" cy="4" r="1.2" fill="currentColor" />
              <circle cx="5" cy="9" r="1.2" fill="currentColor" />
              <circle cx="5" cy="14" r="1.2" fill="currentColor" />
              <circle cx="5" cy="19" r="1.2" fill="currentColor" />
            </svg>
          </div>
          <div style={{
      flex: previewWidth ? 1 : "0 0 24px",
      minWidth: "24px",
      background: "repeating-linear-gradient(-45deg, transparent, transparent 3px, var(--border, #e5e7eb) 3px, var(--border, #e5e7eb) 4px)",
      opacity: 0.4
    }} />
          {previewWidth && <div style={{
      position: "absolute",
      bottom: "8px",
      right: "8px",
      background: "var(--background, white)",
      border: "1px solid var(--border, #e5e7eb)",
      borderRadius: "4px",
      padding: "1px 6px",
      fontSize: "11px",
      fontFamily: "monospace",
      color: "var(--muted-foreground, #6b7280)",
      pointerEvents: "none"
    }}>
              {previewWidth}px
            </div>}
        </div>
        {playgroundHref && <div style={{
      display: "flex",
      justifyContent: "flex-end",
      padding: "4px 0 8px"
    }}>
            <a href={playgroundHref} target="_blank" rel="noopener noreferrer" style={{
      fontSize: "11px",
      opacity: 0.4,
      textDecoration: "none",
      textDecorationLine: "none",
      borderBottom: "none",
      boxShadow: "none",
      display: "inline-flex",
      alignItems: "center",
      gap: "3px",
      transition: "opacity 0.15s",
      fontWeight: 400
    }} onMouseOver={function (e) {
      e.currentTarget.style.opacity = "0.6";
    }} onMouseOut={function (e) {
      e.currentTarget.style.opacity = "0.4";
    }}>
              Edit in Playground
              <svg xmlns="http://www.w3.org/2000/svg" width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M15 3h6v6" /><path d="M10 14 21 3" /><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" /></svg>
            </a>
          </div>}
        <div style={{
      marginBottom: "-2rem"
    }}>{children}</div>
      </Card>;
  }
  return <Card>
      <div ref={cardRef} />
      <div ref={hostRef} />
      {playgroundHref && <div style={{
    display: "flex",
    justifyContent: "flex-end",
    padding: "4px 0 8px"
  }}>
          <a href={playgroundHref} target="_blank" rel="noopener noreferrer" style={{
    fontSize: "11px",
    opacity: 0.4,
    textDecoration: "none",
    textDecorationLine: "none",
    borderBottom: "none",
    boxShadow: "none",
    display: "inline-flex",
    alignItems: "center",
    gap: "3px",
    transition: "opacity 0.15s",
    fontWeight: 400
  }} onMouseOver={function (e) {
    e.currentTarget.style.opacity = "0.6";
  }} onMouseOut={function (e) {
    e.currentTarget.style.opacity = "0.4";
  }}>
            Edit in Playground
            <svg xmlns="http://www.w3.org/2000/svg" width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M15 3h6v6" /><path d="M10 14 21 3" /><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" /></svg>
          </a>
        </div>}
      <div style={{
    marginBottom: "-2rem"
  }}>{children}</div>
    </Card>;
};

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":{"cssClass":"w-fit","name":"select_2","type":"Select","placeholder":"Choose size...","size":"default","disabled":false,"required":false,"invalid":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="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgU2VsZWN0LCBTZWxlY3RPcHRpb24KCndpdGggU2VsZWN0KHBsYWNlaG9sZGVyPSJDaG9vc2Ugc2l6ZS4uLiIsIGNzc19jbGFzcz0idy1maXQiKToKICAgIFNlbGVjdE9wdGlvbih2YWx1ZT0ic20iLCBsYWJlbD0iU21hbGwiKQogICAgU2VsZWN0T3B0aW9uKHZhbHVlPSJtZCIsIGxhYmVsPSJNZWRpdW0iKQogICAgU2VsZWN0T3B0aW9uKHZhbHVlPSJsZyIsIGxhYmVsPSJMYXJnZSIpCg">
  <CodeGroup>
    ```python Python icon="python" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    from prefab_ui.components import Select, SelectOption

    with Select(placeholder="Choose size...", css_class="w-fit"):
        SelectOption(value="sm", label="Small")
        SelectOption(value="md", label="Medium")
        SelectOption(value="lg", label="Large")
    ```

    ```json Protocol icon="brackets-curly" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    {
      "view": {
        "cssClass": "w-fit",
        "name": "select_2",
        "type": "Select",
        "placeholder": "Choose size...",
        "size": "default",
        "disabled": false,
        "required": false,
        "invalid": 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":{"cssClass":"w-fit mx-auto","name":"select_3","type":"Select","placeholder":"Select country","size":"default","disabled":false,"required":false,"invalid":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="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgU2VsZWN0LCBTZWxlY3RPcHRpb24KCndpdGggU2VsZWN0KHBsYWNlaG9sZGVyPSJTZWxlY3QgY291bnRyeSIsIGNzc19jbGFzcz0idy1maXQgbXgtYXV0byIpOgogICAgU2VsZWN0T3B0aW9uKHZhbHVlPSJ1cyIsIGxhYmVsPSJVbml0ZWQgU3RhdGVzIikKICAgIFNlbGVjdE9wdGlvbih2YWx1ZT0idWsiLCBsYWJlbD0iVW5pdGVkIEtpbmdkb20iLCBzZWxlY3RlZD1UcnVlKQogICAgU2VsZWN0T3B0aW9uKHZhbHVlPSJjYSIsIGxhYmVsPSJDYW5hZGEiKQo">
  <CodeGroup>
    ```python Python icon="python" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    from prefab_ui.components import Select, SelectOption

    with Select(placeholder="Select country", css_class="w-fit mx-auto"):
        SelectOption(value="us", label="United States")
        SelectOption(value="uk", label="United Kingdom", selected=True)
        SelectOption(value="ca", label="Canada")
    ```

    ```json Protocol icon="brackets-curly" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    {
      "view": {
        "cssClass": "w-fit mx-auto",
        "name": "select_3",
        "type": "Select",
        "placeholder": "Select country",
        "size": "default",
        "disabled": false,
        "required": false,
        "invalid": 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 w-fit min-w-[200px] mx-auto","type":"Column","children":[{"name":"select_4","type":"Select","placeholder":"Default size","size":"default","disabled":false,"required":false,"invalid":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,"invalid":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="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgQ29sdW1uLCBTZWxlY3QsIFNlbGVjdE9wdGlvbgoKd2l0aCBDb2x1bW4oZ2FwPTQsIGNzc19jbGFzcz0idy1maXQgbWluLXctWzIwMHB4XSBteC1hdXRvIik6CiAgICB3aXRoIFNlbGVjdChwbGFjZWhvbGRlcj0iRGVmYXVsdCBzaXplIik6CiAgICAgICAgU2VsZWN0T3B0aW9uKHZhbHVlPSIxIiwgbGFiZWw9Ik9wdGlvbiAxIikKICAgICAgICBTZWxlY3RPcHRpb24odmFsdWU9IjIiLCBsYWJlbD0iT3B0aW9uIDIiKQoKICAgIHdpdGggU2VsZWN0KHBsYWNlaG9sZGVyPSJTbWFsbCBzaXplIiwgc2l6ZT0ic20iKToKICAgICAgICBTZWxlY3RPcHRpb24odmFsdWU9IjEiLCBsYWJlbD0iT3B0aW9uIDEiKQogICAgICAgIFNlbGVjdE9wdGlvbih2YWx1ZT0iMiIsIGxhYmVsPSJPcHRpb24gMiIpCg">
  <CodeGroup>
    ```python Python icon="python" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    from prefab_ui.components import Column, Select, SelectOption

    with Column(gap=4, css_class="w-fit min-w-[200px] mx-auto"):
        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" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    {
      "view": {
        "cssClass": "gap-4 w-fit min-w-[200px] mx-auto",
        "type": "Column",
        "children": [
          {
            "name": "select_4",
            "type": "Select",
            "placeholder": "Default size",
            "size": "default",
            "disabled": false,
            "required": false,
            "invalid": 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,
            "invalid": 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 w-fit mx-auto","type":"Column","children":[{"type":"Label","text":"Preferred language","optional":false},{"name":"select_6","type":"Select","placeholder":"Choose language","size":"default","disabled":false,"required":false,"invalid":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="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgQ29sdW1uLCBMYWJlbCwgU2VsZWN0LCBTZWxlY3RPcHRpb24KCndpdGggQ29sdW1uKGdhcD0yLCBjc3NfY2xhc3M9InctZml0IG14LWF1dG8iKToKICAgIExhYmVsKCJQcmVmZXJyZWQgbGFuZ3VhZ2UiKQogICAgd2l0aCBTZWxlY3QocGxhY2Vob2xkZXI9IkNob29zZSBsYW5ndWFnZSIpOgogICAgICAgIFNlbGVjdE9wdGlvbih2YWx1ZT0iZW4iLCBsYWJlbD0iRW5nbGlzaCIpCiAgICAgICAgU2VsZWN0T3B0aW9uKHZhbHVlPSJlcyIsIGxhYmVsPSJTcGFuaXNoIikKICAgICAgICBTZWxlY3RPcHRpb24odmFsdWU9ImZyIiwgbGFiZWw9IkZyZW5jaCIpCg">
  <CodeGroup>
    ```python Python icon="python" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    from prefab_ui.components import Column, Label, Select, SelectOption

    with Column(gap=2, css_class="w-fit mx-auto"):
        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" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    {
      "view": {
        "cssClass": "gap-2 w-fit mx-auto",
        "type": "Column",
        "children": [
          {"type": "Label", "text": "Preferred language", "optional": false},
          {
            "name": "select_6",
            "type": "Select",
            "placeholder": "Choose language",
            "size": "default",
            "disabled": false,
            "required": false,
            "invalid": 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>

## Disabled State

<ComponentPreview json={{"view":{"cssClass":"w-fit mx-auto","name":"select_7","type":"Select","placeholder":"Travel class...","size":"default","disabled":true,"required":false,"invalid":false,"children":[{"type":"SelectOption","value":"first","label":"First Class","selected":false,"disabled":false},{"type":"SelectOption","value":"business","label":"Business","selected":false,"disabled":false},{"type":"SelectOption","value":"economy","label":"Economy","selected":false,"disabled":false}]}}} playground="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgU2VsZWN0LCBTZWxlY3RPcHRpb24KCndpdGggU2VsZWN0KAogICAgcGxhY2Vob2xkZXI9IlRyYXZlbCBjbGFzcy4uLiIsCiAgICBkaXNhYmxlZD1UcnVlLAogICAgY3NzX2NsYXNzPSJ3LWZpdCBteC1hdXRvIiwKKToKICAgIFNlbGVjdE9wdGlvbih2YWx1ZT0iZmlyc3QiLCBsYWJlbD0iRmlyc3QgQ2xhc3MiKQogICAgU2VsZWN0T3B0aW9uKHZhbHVlPSJidXNpbmVzcyIsIGxhYmVsPSJCdXNpbmVzcyIpCiAgICBTZWxlY3RPcHRpb24odmFsdWU9ImVjb25vbXkiLCBsYWJlbD0iRWNvbm9teSIpCg">
  <CodeGroup>
    ```python Python icon="python" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    from prefab_ui.components import Select, SelectOption

    with Select(
        placeholder="Travel class...",
        disabled=True,
        css_class="w-fit mx-auto",
    ):
        SelectOption(value="first", label="First Class")
        SelectOption(value="business", label="Business")
        SelectOption(value="economy", label="Economy")
    ```

    ```json Protocol icon="brackets-curly" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    {
      "view": {
        "cssClass": "w-fit mx-auto",
        "name": "select_7",
        "type": "Select",
        "placeholder": "Travel class...",
        "size": "default",
        "disabled": true,
        "required": false,
        "invalid": false,
        "children": [
          {
            "type": "SelectOption",
            "value": "first",
            "label": "First Class",
            "selected": false,
            "disabled": false
          },
          {
            "type": "SelectOption",
            "value": "business",
            "label": "Business",
            "selected": false,
            "disabled": false
          },
          {
            "type": "SelectOption",
            "value": "economy",
            "label": "Economy",
            "selected": false,
            "disabled": false
          }
        ]
      }
    }
    ```
  </CodeGroup>
</ComponentPreview>

## Disabled Options

Individual options can be disabled while the rest of the dropdown remains interactive. Disabled options appear dimmed and cannot be selected:

<ComponentPreview json={{"view":{"cssClass":"w-fit mx-auto","name":"select_8","type":"Select","placeholder":"Choose a ship...","size":"default","disabled":false,"required":false,"invalid":false,"children":[{"type":"SelectOption","value":"heart_of_gold","label":"Heart of Gold","selected":false,"disabled":false},{"type":"SelectOption","value":"bistromath","label":"Bistromath","selected":false,"disabled":true},{"type":"SelectOption","value":"vogon_ship","label":"Vogon Constructor Fleet","selected":false,"disabled":false},{"type":"SelectOption","value":"starship_titanic","label":"Starship Titanic","selected":false,"disabled":true}]}}} playground="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgU2VsZWN0LCBTZWxlY3RPcHRpb24KCndpdGggU2VsZWN0KAogICAgcGxhY2Vob2xkZXI9IkNob29zZSBhIHNoaXAuLi4iLAogICAgY3NzX2NsYXNzPSJ3LWZpdCBteC1hdXRvIiwKKToKICAgIFNlbGVjdE9wdGlvbih2YWx1ZT0iaGVhcnRfb2ZfZ29sZCIsIGxhYmVsPSJIZWFydCBvZiBHb2xkIikKICAgIFNlbGVjdE9wdGlvbigKICAgICAgICB2YWx1ZT0iYmlzdHJvbWF0aCIsCiAgICAgICAgbGFiZWw9IkJpc3Ryb21hdGgiLAogICAgICAgIGRpc2FibGVkPVRydWUsCiAgICApCiAgICBTZWxlY3RPcHRpb24odmFsdWU9InZvZ29uX3NoaXAiLCBsYWJlbD0iVm9nb24gQ29uc3RydWN0b3IgRmxlZXQiKQogICAgU2VsZWN0T3B0aW9uKAogICAgICAgIHZhbHVlPSJzdGFyc2hpcF90aXRhbmljIiwKICAgICAgICBsYWJlbD0iU3RhcnNoaXAgVGl0YW5pYyIsCiAgICAgICAgZGlzYWJsZWQ9VHJ1ZSwKICAgICkK">
  <CodeGroup>
    ```python Python icon="python" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    from prefab_ui.components import Select, SelectOption

    with Select(
        placeholder="Choose a ship...",
        css_class="w-fit mx-auto",
    ):
        SelectOption(value="heart_of_gold", label="Heart of Gold")
        SelectOption(
            value="bistromath",
            label="Bistromath",
            disabled=True,
        )
        SelectOption(value="vogon_ship", label="Vogon Constructor Fleet")
        SelectOption(
            value="starship_titanic",
            label="Starship Titanic",
            disabled=True,
        )
    ```

    ```json Protocol icon="brackets-curly" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    {
      "view": {
        "cssClass": "w-fit mx-auto",
        "name": "select_8",
        "type": "Select",
        "placeholder": "Choose a ship...",
        "size": "default",
        "disabled": false,
        "required": false,
        "invalid": false,
        "children": [
          {
            "type": "SelectOption",
            "value": "heart_of_gold",
            "label": "Heart of Gold",
            "selected": false,
            "disabled": false
          },
          {
            "type": "SelectOption",
            "value": "bistromath",
            "label": "Bistromath",
            "selected": false,
            "disabled": true
          },
          {
            "type": "SelectOption",
            "value": "vogon_ship",
            "label": "Vogon Constructor Fleet",
            "selected": false,
            "disabled": false
          },
          {
            "type": "SelectOption",
            "value": "starship_titanic",
            "label": "Starship Titanic",
            "selected": false,
            "disabled": true
          }
        ]
      }
    }
    ```
  </CodeGroup>
</ComponentPreview>

## Invalid State

Set `invalid=True` to flag a select with error styling. Pair it with a `Label` in a form layout to signal that a selection is required or incorrect:

<ComponentPreview json={{"view":{"cssClass":"gap-2 w-fit mx-auto","type":"Column","children":[{"type":"Label","text":"Destination","optional":false},{"name":"select_9","type":"Select","placeholder":"Choose a planet...","size":"default","disabled":false,"required":false,"invalid":true,"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}]}]}}} playground="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgQ29sdW1uLCBMYWJlbCwgU2VsZWN0LCBTZWxlY3RPcHRpb24KCndpdGggQ29sdW1uKGdhcD0yLCBjc3NfY2xhc3M9InctZml0IG14LWF1dG8iKToKICAgIExhYmVsKCJEZXN0aW5hdGlvbiIpCiAgICB3aXRoIFNlbGVjdChwbGFjZWhvbGRlcj0iQ2hvb3NlIGEgcGxhbmV0Li4uIiwgaW52YWxpZD1UcnVlKToKICAgICAgICBTZWxlY3RPcHRpb24odmFsdWU9Im1hZ3JhdGhlYSIsIGxhYmVsPSJNYWdyYXRoZWEiKQogICAgICAgIFNlbGVjdE9wdGlvbih2YWx1ZT0iYmV0ZWxnZXVzZSIsIGxhYmVsPSJCZXRlbGdldXNlIFYiKQogICAgICAgIFNlbGVjdE9wdGlvbih2YWx1ZT0idm9nc3BoZXJlIiwgbGFiZWw9IlZvZ3NwaGVyZSIpCg">
  <CodeGroup>
    ```python Python icon="python" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    from prefab_ui.components import Column, Label, Select, SelectOption

    with Column(gap=2, css_class="w-fit mx-auto"):
        Label("Destination")
        with Select(placeholder="Choose a planet...", invalid=True):
            SelectOption(value="magrathea", label="Magrathea")
            SelectOption(value="betelgeuse", label="Betelgeuse V")
            SelectOption(value="vogsphere", label="Vogsphere")
    ```

    ```json Protocol icon="brackets-curly" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    {
      "view": {
        "cssClass": "gap-2 w-fit mx-auto",
        "type": "Column",
        "children": [
          {"type": "Label", "text": "Destination", "optional": false},
          {
            "name": "select_9",
            "type": "Select",
            "placeholder": "Choose a planet...",
            "size": "default",
            "disabled": false,
            "required": false,
            "invalid": true,
            "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
              }
            ]
          }
        ]
      }
    }
    ```
  </CodeGroup>
</ComponentPreview>

## Option Groups

Organize long option lists into labeled sections with `SelectGroup` and `SelectLabel`. Use `SelectSeparator` to add visual dividers between groups:

<ComponentPreview json={{"view":{"cssClass":"w-fit","name":"select_10","type":"Select","placeholder":"Choose a food...","size":"default","disabled":false,"required":false,"invalid":false,"children":[{"type":"SelectGroup","children":[{"type":"SelectLabel","label":"Fruits"},{"type":"SelectOption","value":"apple","label":"Apple","selected":false,"disabled":false},{"type":"SelectOption","value":"banana","label":"Banana","selected":false,"disabled":false},{"type":"SelectOption","value":"cherry","label":"Cherry","selected":false,"disabled":false}]},{"type":"SelectSeparator"},{"type":"SelectGroup","children":[{"type":"SelectLabel","label":"Vegetables"},{"type":"SelectOption","value":"carrot","label":"Carrot","selected":false,"disabled":false},{"type":"SelectOption","value":"broccoli","label":"Broccoli","selected":false,"disabled":false},{"type":"SelectOption","value":"spinach","label":"Spinach","selected":false,"disabled":false}]}]}}} playground="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgKAogICAgU2VsZWN0LAogICAgU2VsZWN0R3JvdXAsCiAgICBTZWxlY3RMYWJlbCwKICAgIFNlbGVjdE9wdGlvbiwKICAgIFNlbGVjdFNlcGFyYXRvciwKKQoKd2l0aCBTZWxlY3QocGxhY2Vob2xkZXI9IkNob29zZSBhIGZvb2QuLi4iLCBjc3NfY2xhc3M9InctZml0Iik6CiAgICB3aXRoIFNlbGVjdEdyb3VwKCk6CiAgICAgICAgU2VsZWN0TGFiZWwoIkZydWl0cyIpCiAgICAgICAgU2VsZWN0T3B0aW9uKHZhbHVlPSJhcHBsZSIsIGxhYmVsPSJBcHBsZSIpCiAgICAgICAgU2VsZWN0T3B0aW9uKHZhbHVlPSJiYW5hbmEiLCBsYWJlbD0iQmFuYW5hIikKICAgICAgICBTZWxlY3RPcHRpb24odmFsdWU9ImNoZXJyeSIsIGxhYmVsPSJDaGVycnkiKQogICAgU2VsZWN0U2VwYXJhdG9yKCkKICAgIHdpdGggU2VsZWN0R3JvdXAoKToKICAgICAgICBTZWxlY3RMYWJlbCgiVmVnZXRhYmxlcyIpCiAgICAgICAgU2VsZWN0T3B0aW9uKHZhbHVlPSJjYXJyb3QiLCBsYWJlbD0iQ2Fycm90IikKICAgICAgICBTZWxlY3RPcHRpb24odmFsdWU9ImJyb2Njb2xpIiwgbGFiZWw9IkJyb2Njb2xpIikKICAgICAgICBTZWxlY3RPcHRpb24odmFsdWU9InNwaW5hY2giLCBsYWJlbD0iU3BpbmFjaCIpCg">
  <CodeGroup>
    ```python Python icon="python" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    from prefab_ui.components import (
        Select,
        SelectGroup,
        SelectLabel,
        SelectOption,
        SelectSeparator,
    )

    with Select(placeholder="Choose a food...", css_class="w-fit"):
        with SelectGroup():
            SelectLabel("Fruits")
            SelectOption(value="apple", label="Apple")
            SelectOption(value="banana", label="Banana")
            SelectOption(value="cherry", label="Cherry")
        SelectSeparator()
        with SelectGroup():
            SelectLabel("Vegetables")
            SelectOption(value="carrot", label="Carrot")
            SelectOption(value="broccoli", label="Broccoli")
            SelectOption(value="spinach", label="Spinach")
    ```

    ```json Protocol icon="brackets-curly" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    {
      "view": {
        "cssClass": "w-fit",
        "name": "select_10",
        "type": "Select",
        "placeholder": "Choose a food...",
        "size": "default",
        "disabled": false,
        "required": false,
        "invalid": false,
        "children": [
          {
            "type": "SelectGroup",
            "children": [
              {"type": "SelectLabel", "label": "Fruits"},
              {
                "type": "SelectOption",
                "value": "apple",
                "label": "Apple",
                "selected": false,
                "disabled": false
              },
              {
                "type": "SelectOption",
                "value": "banana",
                "label": "Banana",
                "selected": false,
                "disabled": false
              },
              {
                "type": "SelectOption",
                "value": "cherry",
                "label": "Cherry",
                "selected": false,
                "disabled": false
              }
            ]
          },
          {"type": "SelectSeparator"},
          {
            "type": "SelectGroup",
            "children": [
              {"type": "SelectLabel", "label": "Vegetables"},
              {
                "type": "SelectOption",
                "value": "carrot",
                "label": "Carrot",
                "selected": false,
                "disabled": false
              },
              {
                "type": "SelectOption",
                "value": "broccoli",
                "label": "Broccoli",
                "selected": false,
                "disabled": false
              },
              {
                "type": "SelectOption",
                "value": "spinach",
                "label": "Spinach",
                "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 w-fit mx-auto","type":"Column","children":[{"name":"select_11","type":"Select","placeholder":"Choose a planet...","size":"default","disabled":false,"required":false,"invalid":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_11 }}","type":"Text"}]}}} playground="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgQ29sdW1uLCBTZWxlY3QsIFNlbGVjdE9wdGlvbiwgVGV4dAoKd2l0aCBDb2x1bW4oZ2FwPTQsIGNzc19jbGFzcz0idy1maXQgbXgtYXV0byIpOgogICAgd2l0aCBTZWxlY3QocGxhY2Vob2xkZXI9IkNob29zZSBhIHBsYW5ldC4uLiIpIGFzIHNlbDoKICAgICAgICBTZWxlY3RPcHRpb24odmFsdWU9Im1hZ3JhdGhlYSIsIGxhYmVsPSJNYWdyYXRoZWEiKQogICAgICAgIFNlbGVjdE9wdGlvbih2YWx1ZT0iYmV0ZWxnZXVzZSIsIGxhYmVsPSJCZXRlbGdldXNlIFYiKQogICAgICAgIFNlbGVjdE9wdGlvbih2YWx1ZT0idm9nc3BoZXJlIiwgbGFiZWw9IlZvZ3NwaGVyZSIpCiAgICAgICAgU2VsZWN0T3B0aW9uKHZhbHVlPSJlYXJ0aCIsIGxhYmVsPSJFYXJ0aCAoTW9zdGx5IEhhcm1sZXNzKSIpCiAgICBUZXh0KGYiWW91IGNob3NlOiB7c2VsLnJ4fSIpCg">
  <CodeGroup>
    ```python Python icon="python" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    from prefab_ui.components import Column, Select, SelectOption, Text

    with Column(gap=4, css_class="w-fit mx-auto"):
        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" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    {
      "view": {
        "cssClass": "gap-4 w-fit mx-auto",
        "type": "Column",
        "children": [
          {
            "name": "select_11",
            "type": "Select",
            "placeholder": "Choose a planet...",
            "size": "default",
            "disabled": false,
            "required": false,
            "invalid": 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_11 }}", "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 w-fit mx-auto","type":"Column","children":[{"name":"select_12","type":"Select","placeholder":"Pick a color...","size":"default","disabled":false,"required":false,"invalid":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="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgQ29sdW1uLCBTZWxlY3QsIFNlbGVjdE9wdGlvbiwgVGV4dApmcm9tIHByZWZhYl91aS5hY3Rpb25zIGltcG9ydCBTZXRTdGF0ZQoKd2l0aCBDb2x1bW4oZ2FwPTQsIGNzc19jbGFzcz0idy1maXQgbXgtYXV0byIpOgogICAgd2l0aCBTZWxlY3QoCiAgICAgICAgcGxhY2Vob2xkZXI9IlBpY2sgYSBjb2xvci4uLiIsCiAgICAgICAgb25fY2hhbmdlPVNldFN0YXRlKCJwaWNrZWQiLCAiWW91IGNob3NlOiB7eyAkZXZlbnQgfX0iKSwKICAgICk6CiAgICAgICAgU2VsZWN0T3B0aW9uKHZhbHVlPSJyZWQiLCBsYWJlbD0iUmVkIikKICAgICAgICBTZWxlY3RPcHRpb24odmFsdWU9ImdyZWVuIiwgbGFiZWw9IkdyZWVuIikKICAgICAgICBTZWxlY3RPcHRpb24odmFsdWU9ImJsdWUiLCBsYWJlbD0iQmx1ZSIpCiAgICBUZXh0KAogICAgICAgICJ7eyBwaWNrZWQgfCBkZWZhdWx0OidNYWtlIGEgc2VsZWN0aW9uJyB9fSIsCiAgICAgICAgY3NzX2NsYXNzPSJ0ZXh0LW11dGVkLWZvcmVncm91bmQiLAogICAgKQo">
  <CodeGroup>
    ```python Python icon="python" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    from prefab_ui.components import Column, Select, SelectOption, Text
    from prefab_ui.actions import SetState

    with Column(gap=4, css_class="w-fit mx-auto"):
        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" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
    {
      "view": {
        "cssClass": "gap-4 w-fit mx-auto",
        "type": "Column",
        "children": [
          {
            "name": "select_12",
            "type": "Select",
            "placeholder": "Pick a color...",
            "size": "default",
            "disabled": false,
            "required": false,
            "invalid": 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="side" type="str | None" default="None">
    Which side of the trigger the dropdown appears on: `"top"`, `"right"`, `"bottom"`, `"left"`.
  </ParamField>

  <ParamField body="align" type="str | None" default="None">
    Alignment of the dropdown relative to the trigger: `"start"`, `"center"`, `"end"`.
  </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="invalid" type="bool" default="False">
    Whether the select shows error styling (red border).
  </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="SelectGroup Parameters">
  <ParamField body="css_class" type="str | None" default="None">
    Additional Tailwind CSS classes.
  </ParamField>
</Card>

<Card icon="code" title="SelectLabel Parameters">
  <ParamField body="label" type="str" required>
    Display text for the group header.
  </ParamField>

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

<Card icon="code" title="SelectSeparator Parameters">
  <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 theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
{
  "type": "Select",
  "id?": "string",
  "onMount?": "any",
  "children?": "[Component]",
  "let?": "object",
  "name?": "string",
  "value?": "string",
  "placeholder?": "string",
  "size?": "sm | default",
  "side?": "top | right | bottom | left",
  "align?": "start | center | end",
  "disabled?": false,
  "required?": false,
  "invalid?": false,
  "onChange?": "Action | Action[]",
  "cssClass?": "string"
}
```

```json SelectGroup theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
{
  "type": "SelectGroup",
  "id?": "string",
  "onMount?": "any",
  "children?": "[Component]",
  "let?": "object",
  "cssClass?": "string"
}
```

```json SelectLabel theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
{
  "type": "SelectLabel",
  "id?": "string",
  "onMount?": "any",
  "label": "string (required)",
  "cssClass?": "string"
}
```

```json SelectSeparator theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
{
  "type": "SelectSeparator",
  "id?": "string",
  "onMount?": "any",
  "cssClass?": "string"
}
```

```json SelectOption theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
{
  "type": "SelectOption",
  "id?": "string",
  "onMount?": "any",
  "value": "string (required)",
  "label": "string (required)",
  "selected?": false,
  "disabled?": false,
  "cssClass?": "string"
}
```

For the complete protocol schema, see [Select](/protocol/select), [SelectGroup](/protocol/select-group), [SelectLabel](/protocol/select-label), [SelectSeparator](/protocol/select-separator), [SelectOption](/protocol/select-option).
