---
title: "Select 컴포넌트 — zenit Zig UI"
description: "단일 선택, 다중 선택, 지우기 가능, 검색 가능한 선택기.트리거, 옵션 패널, 키보드 하이라이트, 지우기 버튼, 선택된 값을 하나의 mount 결과가 관리…"
url: https://zenit.z.express/ko/components/select
language: ko
alternate_en: https://zenit.z.express/components/select.md
alternate_zh: https://zenit.z.express/zh/components/select.md
alternate_es: https://zenit.z.express/es/components/select.md
alternate_ja: https://zenit.z.express/ja/components/select.md
alternate_fr: https://zenit.z.express/fr/components/select.md
alternate_de: https://zenit.z.express/de/components/select.md
project: zenit v0.1.0-alpha (Zig 0.15.2, macOS)
source: https://github.com/version-next/zenit
---

# Select

`ui.widgets.Select`

단일 선택, 다중 선택, 지우기 가능, 검색 가능한 선택기.

[Video](https://zenit.z.express/media/stories/select.mp4?v=643a73c940)

**BEHAVIOR CONTRACT**

트리거, 옵션 패널, 키보드 하이라이트, 지우기 버튼, 선택된 값을 하나의 mount 결과가 관리합니다.

**RECORDED INTERACTION**

harness가 아이콘이 있는 선택기를 열고 Option 2를 선택합니다.

`examples/storybook/select_puqef.zig:63`

```zig
pub fn build(scope: *ui.Scope, cx: *ui.Cx) !*ui.Node {
    const root = try ui.box(cx, .{
        .width = .{ .px = 352 },
        .direction = .column,
        .gap = 16,
    }, .{});
    root.meta.ownership.meta.test_id = "story.select.family";
    try root.appendChild(cx.allocator, try ui.text(cx, "Select", .{
        .font_size = 12,
        .font_weight = 600,
        .line_height = 1.2,
        .color = ui.Color.hex(0x1A1A1A),
    }));

    const with_icon = try appendSelect(root, "With icon", .{
        .size = .lg, // puQEf 设计稿为 LG；Select 默认已统一为 md
        .options = &icon_options,
        .leading_icon = ui.icons.globe,
    }, "story.select.with-icon", scope, cx);
    with_icon.panel.meta.ownership.meta.test_id = "story.select.with-icon.panel";
    with_icon.state.chevron_down.meta.ownership.meta.test_id = "story.select.with-icon.chevron";
    for (with_icon.state.option_nodes, 0..) |node, i| {
        node.meta.ownership.meta.test_id = switch (i) {
            0 => "story.select.with-icon.option-1",
            1 => "story.select.with-icon.option-2",
            2 => "story.select.with-icon.option-3",
            else => "story.select.with-icon.option-4",
        };
    }

    const clearable = try appendSelect(root, "Clearable", .{
        .size = .lg, // puQEf 设计稿为 LG；Select 默认已统一为 md
        .options = &options,
        .clearable = true,
        .initial_selected = &.{0},
    }, "story.select.clearable", scope, cx);
    clearable.panel.meta.ownership.meta.test_id = "story.select.clearable.panel";
    clearable.state.clear_button.?.meta.ownership.meta.test_id = "story.select.clear";
    clearable.state.append_slot.meta.ownership.meta.test_id = "story.select.clearable.append";
    clearable.state.append_comp.meta.ownership.meta.test_id = "story.select.clearable.append-comp";
    clearable.state.chevron_slot.meta.ownership.meta.test_id = "story.select.clearable.chevron";
    clearable.state.chevron_up.meta.ownership.meta.test_id = "story.select.clearable.chevron-up";
    clearable.state.chevron_down.meta.ownership.meta.test_id = "story.select.clearable.chevron-down";

    const searchable = try appendSelect(root, "Searchable", .{
        .size = .lg, // puQEf 设计稿为 LG；Select 默认已统一为 md
        .options = &search_options,
        .searchable = true,
        .placeholder = "Search options...",
        .initial_selected = &.{0},
        .show_selected_value_in_search = false,
    }, "story.select.trigger", scope, cx);
    searchable.panel.meta.ownership.meta.test_id = "story.select.panel";
    searchable.state.leading_icon_node.?.meta.ownership.meta.test_id = "story.select.search.icon";
    searchable.state.append_slot.meta.ownership.meta.test_id = "story.select.search.append";
    searchable.state.input_state.?.input_container_node.?.meta.ownership.meta.test_id = "story.select.search.input";
    for (searchable.state.option_nodes, 0..) |node, i| {
        node.meta.ownership.meta.test_id = switch (i) {
            0 => "story.select.search.option-1",
            1 => "story.select.search.option-2",
            2 => "story.select.search.option-3",
            else => unreachable,
        };
    }

    const multi_lg = try appendSelect(root, "Multiple · LG", .{
        .size = .lg, // puQEf 设计稿为 LG；Select 默认已统一为 md
        .options = &options,
        .mode = .multiple,
        .initial_selected = &.{ 0, 1 },
    }, "story.select.multiple-lg", scope, cx);
    multi_lg.panel.meta.ownership.meta.test_id = "story.select.multiple-lg.panel";
    for (multi_lg.state.option_nodes, 0..) |node, i| {
        node.meta.ownership.meta.test_id = switch (i) {
            0 => "story.select.multiple-lg.option-1",
            1 => "story.select.multiple-lg.option-2",
            2 => "story.select.multiple-lg.option-3",
            else => "story.select.multiple-lg.option-4",
        };
    }
    multi_lg.state.tag_nodes[2].meta.ownership.meta.test_id = "story.select.multiple-lg.tag-3";
    multi_lg.state.tag_nodes[2].children.items[1].meta.ownership.meta.test_id = "story.select.multiple-lg.tag-3-close";

    const multi_search_lg = try appendSelect(root, "Multiple searchable · LG", .{
        .size = .lg, // puQEf 设计稿为 LG；Select 默认已统一为 md
        .options = &search_options,
        .mode = .multiple,
        .searchable = true,
        .initial_selected = &.{0},
    }, "story.select.multiple-search-lg", scope, cx);
    multi_search_lg.panel.meta.ownership.meta.test_id = "story.select.multiple-search-lg.panel";
    multi_search_lg.state.content_slot.meta.ownership.meta.test_id = "story.select.multiple-search-lg.content";
    multi_search_lg.state.append_slot.meta.ownership.meta.test_id = "story.select.multiple-search-lg.append";
    multi_search_lg.state.input_state.?.input_container_node.?.meta.ownership.meta.test_id = "story.select.multiple-search-lg.input";
    multi_search_lg.state.option_nodes[2].meta.ownership.meta.test_id = "story.select.multiple-search-lg.option-3";

    const multi_md = try appendSelect(root, "Multiple · MD", .{
        .options = &options,
        .mode = .multiple,
        .size = .md,
        .initial_selected = &.{ 0, 1 },
    }, "story.select.multiple-md", scope, cx);
    multi_md.panel.meta.ownership.meta.test_id = "story.select.multiple-md.panel";

    const multi_search_md = try appendSelect(root, "Multiple searchable · MD", .{
        .options = &search_options,
        .mode = .multiple,
        .size = .md,
        .searchable = true,
        .initial_selected = &.{0},
    }, "story.select.multiple-search-md", scope, cx);
    multi_search_md.panel.meta.ownership.meta.test_id = "story.select.multiple-search-md.panel";
    multi_search_md.state.input_state.?.input_container_node.?.meta.ownership.meta.test_id = "story.select.multiple-search-md.input";
    multi_search_md.state.option_nodes[2].meta.ownership.meta.test_id = "story.select.multiple-search-md.option-3";

    const multi_xs = try appendSelect(root, "Multiple · XS", .{
        .options = &options,
        .mode = .multiple,
        .size = .xs,
        .initial_selected = &.{ 0, 1 },
    }, "story.select.multiple-xs", scope, cx);
    multi_xs.panel.meta.ownership.meta.test_id = "story.select.multiple-xs.panel";

    const multi_search_xs = try appendSelect(root, "Multiple searchable · XS", .{
        .options = &search_options,
        .mode = .multiple,
        .size = .xs,
        .searchable = true,
        .initial_selected = &.{0},
    }, "story.select.multiple-search-xs", scope, cx);
    multi_search_xs.panel.meta.ownership.meta.test_id = "story.select.multiple-search-xs.panel";
    multi_search_xs.state.input_state.?.input_container_node.?.meta.ownership.meta.test_id = "story.select.multiple-search-xs.input";
    multi_search_xs.state.option_nodes[2].meta.ownership.meta.test_id = "story.select.multiple-search-xs.option-3";
    return root;
}
```

[GitHub에서 소스 보기examples/storybook/select\_puqef.zig:63](https://github.com/version-next/zenit/blob/HEAD/examples/storybook/select_puqef.zig#L63)

Storybook에 있는 이 story의 원본 코드입니다(zenit 5f9add5+wip 2026-09-30). `W`는 `ui.widgets`이며, `col` / `row` / `label`은 Storybook 내부의 작은 레이아웃 헬퍼입니다.

### SelectProps

`ui.widgets.Select`

[src/ui/components/select/mod.zig:41](https://github.com/version-next/zenit/blob/HEAD/src/ui/components/select/mod.zig#L41)

```zig
fn mountSelect(props: SelectProps, scope: *Scope, cx: *Cx) !SelectMount
```

| 필드 | 타입 | 기본값 | 설명 |
| --- | --- | --- | --- |
| `options` | `[]const SelectOption` | `&.{}` | — |
| `placeholder` | `[]const u8` | `"Select an option..."` | — |
| `width` | `f32` | `352` | — |
| `size` | `SelectSize` | `.md` | — |
| `mode` | `SelectMode` `.single` | `.single` | — |
| `searchable` | `bool` | `false` | — |
| `show_selected_value_in_search` | `bool` | `true` | Keep the selected label in a searchable single-select trigger. Set to false for search-first presentations where the trigger should retain its search placeholder while the selected row remains checked. |
| `clearable` | `bool` | `false` | — |
| `leading_icon` | `?svg_assets.Asset` | `null` | — |
| `initial_selected` | `[]const usize` | `&.{}` | — |
| `disabled` | `bool` | `false` | — |
| `max_dropdown_height` | `f32` | `280` | — |
| `on_change` | `?core.HandlerRef` | `null` | — |

### SelectMount

`ui.widgets.Select`

[src/ui/components/select/mod.zig:217](https://github.com/version-next/zenit/blob/HEAD/src/ui/components/select/mod.zig#L217)

| 필드 | 타입 | 기본값 | 설명 |
| --- | --- | --- | --- |
| `wrapper` | `*Node` | — | — |
| `trigger` | `*Node` | — | — |
| `panel` | `*Node` | — | — |
| `state` | `*SelectState` | — | — |
| `is_open` | `*Signal(bool)` | — | — |
