# Picker

Pickers enable users to pick an option from a collapsible list of options, often used when the space is limited.

## Example

```python
from deephaven import ui


@ui.component
def ui_picker_basic():
    option, set_option = ui.use_state("")

    return ui.picker(
        "Rarely",
        "Sometimes",
        "Always",
        label="Choose frequency",
        selected_key=option,
        on_selection_change=set_option,
    )


my_picker_basic = ui_picker_basic()
```

## UI recommendations

Recommendations for creating pickers:

1. Every picker should have a [label]() specified. Without one, the picker is ambiguous. In the rare case that context is sufficient, the label is unnecessary; you must still include an aria-label via the `aria_label` prop.
2. Options in the picker should be kept short and concise; multiple lines are strongly discouraged.
3. The picker’s width should be set so that the field button does not prevent options being displayed in full.
4. The label, menu items, and placeholder text should all be in sentence case.
5. A picker’s help text should provide actionable guidance on what to select and how to select it, offering additional context without repeating the label.
6. When an error occurs, the help text specified in a picker should be replaced by error text.
7. Write error messages in a concise and helpful manner, guiding users to resolve the issue. Error text should be 1-2 short, complete sentences ending with a period.

## Data sources

We can use a Deephaven table as a data source to populate the options for pickers. A table automatically uses the first column as both the key and label. If there are duplicate keys, an error will be thrown; to avoid this, a `select_distinct` can be used on the table before using it as a picker data source.

```python
from deephaven import ui
from deephaven.plot import express as dx

stocks = dx.data.stocks().select_distinct("Sym")

my_picker_table_source_example = ui.picker(stocks, label="Stock Symbol Picker")
```

If you wish to specify the keys and labels manually, you can use a  `ui.item_table_source` to dynamically derive the options from a table.

```python
from deephaven import ui, empty_table

icon_names = ["vsAccount"]
columns = [
    "Key=new Integer(i)",
    "Label=new String(`Display `+i)",
    "Icon=(String) icon_names[0]",
]
column_types = empty_table(20).update(columns)

item_table_source = ui.item_table_source(
    column_types,
    key_column="Key",
    label_column="Label",
    icon_column="Icon",
)

my_picker_item_table_source_example = ui.picker(item_table_source, label="User Picker")
```

## Labeling

The picker can be labeled using the `label` prop. If no label is provided, an `aria_label` must be provided to identify the control for accessibility purposes.

```python
from deephaven import ui


@ui.component
def ui_picker_label_examples():
    return [
        ui.picker(
            ui.item("Option 1"),
            ui.item("Option 2"),
            ui.item("Option 3"),
            label="Pick an option",
        ),
        ui.picker(
            ui.item("Option 1"),
            ui.item("Option 2"),
            ui.item("Option 3"),
            ui.item("Option 4"),
            aria_label="Pick an option",
        ),
    ]


my_picker_label_examples = ui_picker_label_examples()
```

The `is_required` prop and the `necessity_indicator` props can be used to show whether selecting an option in the picker is required or optional.

When the `necessity_indicator` prop is set to “label”, a localized string will be generated for “(required)” or “(optional)” automatically.

```python
from deephaven import ui


@ui.component
def ui_picker_required_examples():
    return [
        ui.picker(
            ui.item("Option 1"),
            ui.item("Option 2"),
            ui.item("Option 3"),
            label="Pick an option",
            is_required=True,
        ),
        ui.picker(
            ui.item("Option 1"),
            ui.item("Option 2"),
            ui.item("Option 3"),
            ui.item("Option 4"),
            label="Pick an option",
            is_required=True,
            necessity_indicator="label",
        ),
        ui.picker(
            ui.item("Option 1"),
            ui.item("Option 2"),
            ui.item("Option 3"),
            ui.item("Option 4"),
            label="Pick an option",
            necessity_indicator="label",
        ),
    ]


my_picker_required_examples = ui_picker_required_examples()
```

## Selection

In a picker, the `default_selected_key` or `selected_key` props set a selected option.

```python
from deephaven import ui


@ui.component
def ui_picker_selected_key_examples():
    option, set_option = ui.use_state("Option 1")
    return [
        ui.picker(
            ui.item("Option 1"),
            ui.item("Option 2"),
            ui.item("Option 3"),
            default_selected_key="Option 2",
            label="Pick an option (uncontrolled)",
        ),
        ui.picker(
            ui.item("Option 1"),
            ui.item("Option 2"),
            ui.item("Option 3"),
            ui.item("Option 4"),
            selected_key=option,
            on_selection_change=set_option,
            label="Pick an option (controlled)",
        ),
    ]


my_picker_selected_key_examples = ui_picker_selected_key_examples()
```

## HTML Forms

Pickers can support a `name` prop for integration with HTML forms, allowing for easy identification of a value on form submission.

```python
from deephaven import ui


my_picker_name_example = ui.form(
    ui.flex(ui.picker(ui.item("Option 1"), ui.item("Option 2"), name="Sample Name"))
)
```

## Sections

Picker supports sections that group options. Sections can be used by wrapping groups of items in a `section` element. Each section takes a `title` and `key` prop.

```python
from deephaven import ui

my_picker_section_example = ui.picker(
    ui.section(ui.item("Option 1"), ui.item("Option 2"), title="Section 1"),
    ui.section(ui.item("Option 3"), ui.item("Option 4"), title="Section 2"),
)
```

## Events

The Picker component supports selection through mouse, keyboard, and touch inputs via the `on_selection_change` prop, which receives the selected key as an argument.

```python
from deephaven import ui


@ui.component
def ui_picker_event_example():
    value, set_value = ui.use_state("")
    return ui.form(
        ui.picker(
            ui.section(ui.item("Option 1"), ui.item("Option 2"), title="Section 1"),
            on_selection_change=set_value,
        )
    )


my_picker_event_example = ui_picker_event_example()
```

## Complex items

Items within a picker can include additional content to better convey options. You can add icons, avatars, and descriptions to the children of an `ui.item`. When adding a description, set the `slot` prop to “description” to differentiate between the text elements.

```python
from deephaven import ui

my_picker_complex_items_example = ui.picker(
    ui.item(
        ui.icon("vsGithubAlt"),
        ui.text("Github"),
        ui.text("Github Option", slot="description"),
        text_value="Github",
    ),
    ui.item(
        ui.icon("vsAzureDevops"),
        ui.text("Azure"),
        ui.text("Azure Option", slot="description"),
        text_value="Azure",
    ),
)
```

## Loading

The `is_loading` prop displays a progress circle indicating that the picker is loading or processing data, which can be used to give immediate visual feedback to users. It also prevents users from interacting with the picker while data is loading, avoiding potential bad states.

```python
from deephaven import ui


@ui.component
def ui_picker_loading_example():
    loading, set_loading = ui.use_state("loading")
    return ui.form(
        ui.picker(
            ui.section(ui.item("Option 1"), ui.item("Option 2"), title="Section 1"),
            is_loading=True if loading == "loading" else False,
        )
    )


my_picker_loading_example = ui_picker_loading_example()
```

## Validation

The `is_required` prop ensures that the user selects an option. The related `validation_behaviour` prop allows the user to specify aria or native verification.

When the prop is set to “native”, the validation errors block form submission and are displayed as help text automatically.

```python
from deephaven import ui


@ui.component
def ui_picker_validation_behaviour_example():
    return ui.form(
        ui.picker(
            ui.section(ui.item("Option 1"), ui.item("Option 2"), title="Section 1"),
            validation_behavior="native",
            is_required=True,
        )
    )


my_picker_validation_behaviour_example = ui_picker_validation_behaviour_example()
```

## Label position

By default, the position of a picker’s label is above the picker, but it can be moved to the side using the `label_position` prop.

```python
from deephaven import ui


@ui.component
def ui_picker_label_position_examples():
    return [
        ui.picker(
            ui.section(ui.item("Option 1"), ui.item("Option 2"), title="Section 1"),
            label="Test Label",
        ),
        ui.picker(
            ui.section(ui.item("Option 1"), ui.item("Option 2"), title="Section 1"),
            label="Test Label",
            label_position="side",
        ),
    ]


my_picker_label_position_examples = ui_picker_label_position_examples()
```

## Quiet state

The `is_quiet` prop makes a picker “quiet”. This can be useful when the picker and its corresponding styling should not distract users from surrounding content.

```python
from deephaven import ui


my_picker_is_quiet_example = ui.picker(
    ui.section(ui.item("Option 1"), ui.item("Option 2"), title="Section 1"),
    is_quiet=True,
)
```

## Disabled state

The `is_disabled` prop disables a picker to prevent user interaction. This is useful when the picker should be visible but not available for selection.

```python
from deephaven import ui


my_picker_is_disabled_example = ui.picker(
    ui.section(ui.item("Option 1"), ui.item("Option 2"), title="Section 1"),
    is_disabled=True,
)
```

## Help text

A picker can have both a `description` and an `error_message`. Use the error message to offer specific guidance on how to correct the input.

The `is_invalid` prop can be used to set whether the current picker state is valid or invalid.

```python
from deephaven import ui


@ui.component
def ui_picker_help_text_examples():
    return [
        ui.picker(
            ui.section(ui.item("Option 1"), ui.item("Option 2"), title="Section 1"),
            label="Sample Label",
            description="Enter a comment.",
        ),
        ui.picker(
            ui.section(ui.item("Option 1"), ui.item("Option 2"), title="Section 1"),
            label="Sample Label",
            is_invalid=False,
            error_message="Sample invalid error message.",
        ),
        ui.picker(
            ui.section(ui.item("Option 1"), ui.item("Option 2"), title="Section 1"),
            label="Sample Label",
            is_invalid=True,
            error_message="Sample invalid error message.",
        ),
    ]


my_picker_help_text_examples = ui_picker_help_text_examples()
```

## Contextual help

Using the `contextual_help` prop, a `ui.contextual_help` can be placed next to the label to provide additional information about the picker.

```python
from deephaven import ui


picker_contextual_help_example = ui.picker(
    ui.section(ui.item("Option 1"), ui.item("Option 2"), title="Section 1"),
    label="Sample Label",
    contextual_help=ui.contextual_help(ui.heading("Content tips")),
)
```

## Custom width

The `width` prop adjusts the width of a picker, and the `max_width` prop enforces a maximum width.

```python
from deephaven import ui


@ui.component
def ui_picker_width_examples():
    return [
        ui.picker(
            ui.section(ui.item("Option 1"), ui.item("Option 2"), title="Section 1"),
            width="size-3600",
        ),
        ui.picker(
            ui.section(ui.item("Option 1"), ui.item("Option 2"), title="Section 1"),
            width="size-3600",
            max_width="100%",
        ),
    ]


my_picker_width_examples = ui_picker_width_examples()
```

## Align and direction

The `align` prop sets the text alignment of the options in the picker, while the `direction` prop specifies which direction the menu will open.

It is important to note that the popover will not open in the set `direction` if there is not enough room to open in that direction.

```python
from deephaven import ui


@ui.component
def ui_picker_alignment_direction_examples():
    return ui.flex(
        ui.picker(
            ui.section(ui.item("Option 1"), ui.item("Option 2"), title="Section 1"),
            align="end",
            menu_width="size-3000",
        ),
        ui.picker(
            ui.section(ui.item("Option 1"), ui.item("Option 2"), title="Section 1"),
            direction="top",
        ),
        gap="size-150",
        direction="column",
        padding=40,
    )


my_picker_alignment_direction_examples = ui_picker_alignment_direction_examples()
```

## Menu state

The open state of the picker menu can be controlled through the `is_open` and `default_open` props.

```python
from deephaven import ui


@ui.component
def ui_picker_open_state_examples():
    open, set_open = ui.use_state(False)
    return [
        ui.picker(
            ui.section(ui.item("Option 1"), ui.item("Option 2"), title="Section 1"),
            is_open=open,
            on_open_change=set_open,
        ),
        ui.picker(
            ui.section(ui.item("Option 1"), ui.item("Option 2"), title="Section 1"),
            default_open=True,
        ),
    ]


my_picker_open_state_examples = ui_picker_open_state_examples()
```

## API Reference

A picker that can be used to select from a list. Children should be one of five types:
1. If children are of type Item, they are the dropdown options.
2. If children are of type SectionElement, they are the dropdown sections.
3. If children are of type Table, the values in the table are the dropdown options.

**Returns:** `BaseElement` The rendered Picker.

<ParamTable param={{"module_name": "deephaven.ui.", "name": "picker", "parameters": [{"name": "*children", "type": "str | int | float | bool | BaseElement | Element | Table | PartitionedTable | ItemTableSource", "description": "The options to render within the picker."}, {"name": "default_selected_key", "type": "str | int | float | bool | None", "description": "The initial selected key in the collection (uncontrolled).", "default": "None"}, {"name": "selected_key", "type": "str | int | float | bool | None", "description": "The currently selected key in the collection (controlled).", "default": "None"}, {"name": "on_selection_change", "type": "Callable[[str | int | float | bool], None] | None", "description": "Handler that is called when the selection changes.", "default": "None"}, {"name": "on_change", "type": "Callable[[str | int | float | bool], None] | None", "description": "Alias of on_selection_change. Handler that is called when the selection changes.", "default": "None"}, {"name": "is_quiet", "type": "bool | None", "description": "Whether the TextField should be displayed with a quiet style", "default": "None"}, {"name": "align", "type": "Literal['start', 'end']", "description": "Alignment of the menu relative to the input target.", "default": "'start'"}, {"name": "direction", "type": "Literal['bottom', 'top']", "description": "Direction in which the menu should open relative to the Picker.", "default": "'bottom'"}, {"name": "should_flip", "type": "bool", "description": "Whether the menu should flip when it reaches the viewport boundaries.", "default": "True"}, {"name": "menu_width", "type": "str | float | None", "description": "Width of the menu. By default, matches width of the trigger. Note that the minimum width of the dropdown is always equal to the trigger's width.", "default": "None"}, {"name": "auto_focus", "type": "bool | None", "description": "Whether the input should be focused on render.", "default": "None"}, {"name": "auto_complete", "type": "str | None", "description": "Describes the type of autocomplete functionality the input should provide if any.", "default": "None"}, {"name": "name", "type": "str | None", "description": "Name of the input, used when submitting an HTML form.", "default": "None"}, {"name": "is_open", "type": "bool | None", "description": "Sets the open state of the menu.", "default": "None"}, {"name": "default_open", "type": "bool | None", "description": "Sets the default open state of the menu.", "default": "None"}, {"name": "is_disabled", "type": "bool | None", "description": "Whether the Picker is disabled.", "default": "None"}, {"name": "is_required", "type": "bool | None", "description": "Whether user input on the Picker is required before form submission.", "default": "None"}, {"name": "is_invalid", "type": "bool | None", "description": "Whether the Picker is in an invalid state.", "default": "None"}, {"name": "validation_behavior", "type": "Literal['aria', 'native'] | None", "description": "Whether to use native HTML form validation to prevent form submission when the value is missing or invalid, or mark the field as required or invalid via ARIA.", "default": "None"}, {"name": "description", "type": "Element | None", "description": "A description for the field. Provides a hint such as specific requirements for what to choose.", "default": "None"}, {"name": "error_message", "type": "Element | None", "description": "An error message for the field.", "default": "None"}, {"name": "label", "type": "Element | None", "description": "A label for the field.", "default": "None"}, {"name": "placeholder", "type": "str | None", "description": "Placeholder text for the input.", "default": "None"}, {"name": "is_loading", "type": "bool | None", "description": "Whether the Picker is in a loading state.", "default": "None"}, {"name": "label_position", "type": "Literal['top', 'side']", "description": "The label's overall position relative to the element it is labeling.", "default": "'top'"}, {"name": "label_align", "type": "Literal['start', 'end'] | None", "description": "The label's horizontal alignment relative to the element it is labeling.", "default": "None"}, {"name": "necessity_indicator", "type": "Literal['icon', 'label'] | None", "description": "Whether the required state should be shown as an icon or text.", "default": "None"}, {"name": "contextual_help", "type": "Element | None", "description": "A ContextualHelp element to place next to the label.", "default": "None"}, {"name": "on_open_change", "type": "Callable[[bool], None] | None", "description": "Handler that is called when the open state changes.", "default": "None"}, {"name": "on_focus", "type": "Callable[[FocusEvent], None] | None", "description": "Handler that is called when the input is focused.", "default": "None"}, {"name": "on_blur", "type": "Callable[[FocusEvent], None] | None", "description": "Handler that is called when the input loses focus.", "default": "None"}, {"name": "on_focus_change", "type": "Callable[[bool], None] | None", "description": "Handler that is called when the input is focused or blurred.", "default": "None"}, {"name": "on_key_down", "type": "Callable[[KeyboardEvent], None] | None", "description": "Handler that is called when a key is pressed down.", "default": "None"}, {"name": "on_key_up", "type": "Callable[[KeyboardEvent], None] | None", "description": "Handler that is called when a key is released.", "default": "None"}, {"name": "flex", "type": "str | float | bool | None", "description": "When used in a flex layout, specifies how the element will grow or shrink to fit the space available.", "default": "None"}, {"name": "flex_grow", "type": "float | None", "description": "When used in a flex layout, specifies how much the element will grow to fit the space available.", "default": "None"}, {"name": "flex_shrink", "type": "float | None", "description": "When used in a flex layout, specifies how much the element will shrink to fit the space available.", "default": "None"}, {"name": "flex_basis", "type": "str | float | None", "description": "When used in a flex layout, specifies the initial size of the element.", "default": "None"}, {"name": "align_self", "type": "Literal['auto', 'normal', 'start', 'end', 'center', 'flex-start', 'flex-end', 'self-start', 'self-end', 'stretch'] | None", "description": "Overrides the align_items property of a flex or grid container.", "default": "None"}, {"name": "justify_self", "type": "Literal['auto', 'normal', 'start', 'end', 'flex-start', 'flex-end', 'self-start', 'self-end', 'center', 'left', 'right', 'stretch'] | None", "description": "Specifies how the element is justified inside a flex or grid container.", "default": "None"}, {"name": "order", "type": "int | None", "description": "The layout order for the element within a flex or grid container.", "default": "None"}, {"name": "grid_area", "type": "str | None", "description": "The name of the grid area to place the element in.", "default": "None"}, {"name": "grid_row", "type": "str | None", "description": "The name of the grid row to place the element in.", "default": "None"}, {"name": "grid_row_start", "type": "str | None", "description": "The name of the grid row to start the element in.", "default": "None"}, {"name": "grid_row_end", "type": "str | None", "description": "The name of the grid row to end the element in.", "default": "None"}, {"name": "grid_column", "type": "str | None", "description": "The name of the grid column to place the element in.", "default": "None"}, {"name": "grid_column_start", "type": "str | None", "description": "The name of the grid column to start the element in.", "default": "None"}, {"name": "grid_column_end", "type": "str | None", "description": "The name of the grid column to end the element in.", "default": "None"}, {"name": "margin", "type": "str | float | None", "description": "The margin to apply around the element.", "default": "None"}, {"name": "margin_top", "type": "str | float | None", "description": "The margin to apply above the element.", "default": "None"}, {"name": "margin_bottom", "type": "str | float | None", "description": "The margin to apply below the element.", "default": "None"}, {"name": "margin_start", "type": "str | float | None", "description": "The margin to apply before the element.", "default": "None"}, {"name": "margin_end", "type": "str | float | None", "description": "The margin to apply after the element.", "default": "None"}, {"name": "margin_x", "type": "str | float | None", "description": "The margin to apply to the left and right of the element.", "default": "None"}, {"name": "margin_y", "type": "str | float | None", "description": "The margin to apply to the top and bottom of the element.", "default": "None"}, {"name": "width", "type": "str | float | None", "description": "The width of the element.", "default": "None"}, {"name": "height", "type": "str | float | None", "description": "The height of the element.", "default": "None"}, {"name": "min_width", "type": "str | float | None", "description": "The minimum width of the element.", "default": "None"}, {"name": "min_height", "type": "str | float | None", "description": "The minimum height of the element.", "default": "None"}, {"name": "max_width", "type": "str | float | None", "description": "The maximum width of the element.", "default": "None"}, {"name": "max_height", "type": "str | float | None", "description": "The maximum height of the element.", "default": "None"}, {"name": "position", "type": "Literal['static', 'relative', 'absolute', 'fixed', 'sticky'] | None", "description": "Specifies how the element is positioned.", "default": "None"}, {"name": "top", "type": "str | float | None", "description": "The distance from the top of the containing element.", "default": "None"}, {"name": "bottom", "type": "str | float | None", "description": "The distance from the bottom of the containing element.", "default": "None"}, {"name": "start", "type": "str | float | None", "description": "The distance from the start of the containing element.", "default": "None"}, {"name": "end", "type": "str | float | None", "description": "The distance from the end of the containing element.", "default": "None"}, {"name": "left", "type": "str | float | None", "description": "The distance from the left of the containing element.", "default": "None"}, {"name": "right", "type": "str | float | None", "description": "The distance from the right of the containing element.", "default": "None"}, {"name": "z_index", "type": "int | None", "description": "The stack order of the element.", "default": "None"}, {"name": "is_hidden", "type": "bool | None", "description": "Whether the element is hidden.", "default": "None"}, {"name": "id", "type": "str | None", "description": "A unique identifier for the element.", "default": "None"}, {"name": "exclude_from_tab_order", "type": "bool | None", "description": "Whether the element should be excluded from the tab order.", "default": "None"}, {"name": "aria_label", "type": "str | None", "description": "The label for the element.", "default": "None"}, {"name": "aria_labelledby", "type": "str | None", "description": "The id of the element that labels the element.", "default": "None"}, {"name": "aria_describedby", "type": "str | None", "description": "The id of the element that describes the element.", "default": "None"}, {"name": "aria_details", "type": "str | None", "description": "The details for the element.", "default": "None"}, {"name": "UNSAFE_class_name", "type": "str | None", "description": "A CSS class to apply to the element.", "default": "None"}, {"name": "UNSAFE_style", "type": "Dict[str, Any] | None", "description": "A CSS style to apply to the element.", "default": "None"}, {"name": "key", "type": "str | None", "description": "A unique identifier used by React to render elements in a list.", "default": "None"}]}} />
