# List View

List view displays a list of interactive items, and allows a user to navigate, select, or perform an action. It offers greater flexibility in the contents it can render and can distinguish between row selection and actions performed on a row. This makes list view an ideal component for turning table columns into interactive lists.

## Example

```python
from deephaven import ui


@ui.component
def ui_list_view():
    return ui.list_view(
        ui.item("Option 1"),
        ui.item("Option 2"),
        ui.item("Option 3"),
        ui.item("Option 4"),
        default_selected_keys=["Option 2", "Option 3"],
    )


my_list_view = ui_list_view()
```

## Table Source Example

List view items can also be generated from a table directly or using `item_table_source`.

### Passing Table Directly

This method is ideal for quickly displaying a static dataset. By default, the first column is used as the key and label.

```python
from deephaven import ui, new_table
from deephaven.column import string_col

_colors = new_table(
    [
        string_col("Colors", ["Red", "Blue", "Green"]),
    ]
)


@ui.component
def ui_list_view_table():
    return ui.list_view(_colors)


my_list_view_table = ui_list_view_table()
```

### Using item_table_source

`item_table_source` is used to create complex items from a table (ie., defining which columns are the keys/labels of the data).

```python
from deephaven import ui, new_table
from deephaven.column import string_col

_table = new_table(
    [
        string_col("Keys", ["key-0", "key-1", "key-2"]),
        string_col("Labels", ["Option 0", "Option 1", "Option 2"]),
    ]
)


@ui.component
def ui_list_view_table_source():
    source = ui.item_table_source(_table, key_column="Keys", label_column="Labels")
    return ui.list_view(source)


my_list_view_table_source = ui_list_view_table_source()
```

## Events

List view accepts an action that can be triggered when a user performs an action on an item.

```python
from deephaven import ui, new_table
from deephaven.column import string_col

_table = new_table(
    [
        string_col("Keys", ["key-0", "key-1", "key-2"]),
        string_col("Labels", ["Option 0", "Option 1", "Option 2"]),
    ]
)


@ui.component
def ui_list_view_actions():
    action_item_keys, set_action_item_keys = ui.use_state(["", ""])
    on_action = ui.use_callback(
        lambda action_key, item_key: set_action_item_keys([action_key, str(item_key)]),
        [],
    )

    source = ui.item_table_source(
        _table,
        key_column="Keys",
        label_column="Labels",
        actions=ui.list_action_group(
            "Edit",
            "Delete",
            on_action=on_action,
        ),
    )
    lv = ui.list_view(source)

    text_action = ui.text("Action: " + " ".join(map(str, action_item_keys)))

    return lv, text_action


my_list_view_actions = ui_list_view_actions()
```

List view can also accept a handler that is called when the selection is changed.

```python
from deephaven import ui, new_table
from deephaven.column import string_col

_table = new_table(
    [
        string_col("Keys", ["key-0", "key-1", "key-2"]),
        string_col("Labels", ["Option 0", "Option 1", "Option 2"]),
    ]
)


@ui.component
def ui_list_view_selection():
    value, set_value = ui.use_state(["key-2"])

    def handle_change(e):
        set_value(e)
        print("Selection: " + ", ".join(map(str, e)))

    source = ui.item_table_source(
        _table,
        key_column="Keys",
        label_column="Labels",
    )
    lv = ui.list_view(source, on_change=handle_change)

    return lv


my_list_view_selection = ui_list_view_selection()
```

## Disabled Options

To disable certain rows in the `ListView` component, use the `disabled_keys` prop. By setting this prop with an array of keys, you can prevent interaction with those rows, providing greater control and customization options for the `ListView` behavior.

```python
from deephaven import ui, new_table
from deephaven.column import string_col

_table = new_table(
    [
        string_col("Keys", ["key-0", "key-1", "key-2"]),
        string_col("Labels", ["Option 0", "Option 1", "Option 2"]),
    ]
)


@ui.component
def ui_list_view_disabled():
    value, set_value = ui.use_state(["key-2"])

    source = ui.item_table_source(
        _table,
        key_column="Keys",
        label_column="Labels",
    )
    lv = ui.list_view(
        source, selected_keys=value, on_change=set_value, disabled_keys=["key-0"]
    )

    return lv


my_list_view_disabled = ui_list_view_disabled()
```

## Quiet State

```python
from deephaven import ui


@ui.component
def ui_list_view_quiet():
    value, set_value = ui.use_state(["Text 2"])

    quiet_list = ui.list_view(
        "Text 1",
        "Text 2",
        "Text 3",
        aria_label="List View - Quiet",
        on_change=set_value,
        selected_keys=value,
        is_quiet=True,
    )

    default_list = ui.list_view(
        "Text 1",
        "Text 2",
        "Text 3",
        aria_label="List View - Default",
        on_change=set_value,
        selected_keys=value,
    )
    return quiet_list, default_list


my_list_view_quiet = ui_list_view_quiet()
```

## Modifying Density

To adjust the vertical padding of each row in the list view, use the `density` prop.

```python
from deephaven import ui


@ui.component
def ui_list_view_density():
    value, set_value = ui.use_state(["Text 2"])

    compact_list = ui.list_view(
        "Text 1",
        "Text 2",
        "Text 3",
        aria_label="List View - Compact",
        on_change=set_value,
        selected_keys=value,
        density="compact",
    )

    spacious_list = ui.list_view(
        "Text 1",
        "Text 2",
        "Text 3",
        aria_label="List View - Spacious",
        on_change=set_value,
        selected_keys=value,
        density="spacious",
    )
    return compact_list, spacious_list


my_list_view_density = ui_list_view_density()
```

## Overflow Mode

The default behavior is to truncate content that overflows its row. Text can be wrapped instead by adding `wrap` to the `overflow_mode` prop.

Note: Currently not supported if a table source is used.

```python
from deephaven import ui


@ui.component
def ui_list_view_overflow():
    value, set_value = ui.use_state(["Text 2"])

    truncated_list = ui.list_view(
        "Really long Text 1",
        "Really long Text 2",
        "Really long Text 3",
        aria_label="List View - Quiet",
        on_change=set_value,
        selected_keys=value,
        overflow_mode="truncate",
        width="150px",
    )

    wrapped_list = ui.list_view(
        "Really long Text 1",
        "Really long Text 2",
        "Really long Text 3",
        aria_label="List View - Quiet",
        on_change=set_value,
        selected_keys=value,
        overflow_mode="wrap",
        width="150px",
    )
    return truncated_list, wrapped_list


my_list_view_overflow = ui_list_view_overflow()
```

## API reference

A list view that can be used to create a list of items. Children should be one of three types:
1. If children are of type Item, they are the list items.
2. If children are of type Table, the values in the table are the list items.

**Returns:** `Element` The rendered ListView.

<ParamTable param={{"module_name": "deephaven.ui.", "name": "list_view", "parameters": [{"name": "*children", "type": "str | int | float | bool | BaseElement | Table | ItemTableSource", "description": "The options to render within the list_view."}, {"name": "density", "type": "Literal['COMPACT', 'NORMAL', 'SPACIOUS'] | None", "description": "Sets the amount of vertical padding within each cell.", "default": "'COMPACT'"}, {"name": "is_quiet", "type": "bool | None", "description": "Whether the ListView should use the quiet style.", "default": "None"}, {"name": "loading_state", "type": "Literal['loading', 'sorting', 'loadingMore', 'error', 'idle', 'filtering'] | None", "description": "The loading state of the ListView. Determines whether to show a loading spinner.", "default": "None"}, {"name": "overflow_mode", "type": "Literal['truncate', 'wrap']", "description": "The behaviour of the text when it overflows the cell.", "default": "'truncate'"}, {"name": "render_empty_state", "type": "Element | None", "description": "Sets what the list_view should render when there is no content to display.", "default": "None"}, {"name": "disabled_behavior", "type": "Literal['selection', 'all'] | None", "description": "Whether disabled_keys applies to all interactions or just selection.", "default": "None"}, {"name": "disabled_keys", "type": "Sequence[str | int | float | bool] | None", "description": "The keys that should be disabled. These cannot be selected, focused, or interacted with", "default": "None"}, {"name": "selection_mode", "type": "Literal['SINGLE', 'MULTIPLE'] | None", "description": "By default \"MULTIPLE\", which allows multiple selection. May also be \"SINGLE\" to allow only single selection, or \"None\"/None to allow no selection.", "default": "'MULTIPLE'"}, {"name": "disallow_empty_selection", "type": "bool | None", "description": "Whether the ListView should disallow empty selection.", "default": "None"}, {"name": "selected_keys", "type": "Sequence[str | int | float | bool] | None", "description": "The currently selected keys in the collection (controlled).", "default": "None"}, {"name": "default_selected_keys", "type": "Sequence[str | int | float | bool] | None", "description": "The initial selected keys in the collection (uncontrolled).", "default": "None"}, {"name": "selection_style", "type": "Literal['checkbox', 'highlight'] | None", "description": "How the selection should be displayed.", "default": "None"}, {"name": "on_action", "type": "Callable[[str | int | float | bool, str], None] | None", "description": "Handler that is called when the user performs an action on an item. The user event depends on the collection's selection_style and interaction modality.", "default": "None"}, {"name": "on_change", "type": "Callable[[Sequence[str | int | float | bool]], None] | None", "description": "Handler that is called when the selection changes.", "default": "None"}, {"name": "on_selection_change", "type": "Callable[[Sequence[str | int | float | bool]], None] | None", "description": "Deprecated. Use on_change instead.Handler that is called when the selection changes.", "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 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 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 main 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 alignItems 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": "Species 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": "When used in a grid layout, specifies the named grid area that the element should be placed in within the grid.", "default": "None"}, {"name": "grid_row", "type": "str | None", "description": "When used in a grid layout, specifies the row the element should be placed in within the grid.", "default": "None"}, {"name": "grid_column", "type": "str | None", "description": "When used in a grid layout, specifies the column the element should be placed in within the grid.", "default": "None"}, {"name": "grid_row_start", "type": "str | None", "description": "When used in a grid layout, specifies the starting row to span within the grid.", "default": "None"}, {"name": "grid_row_end", "type": "str | None", "description": "When used in a grid layout, specifies the ending row to span within the grid.", "default": "None"}, {"name": "grid_column_start", "type": "str | None", "description": "When used in a grid layout, specifies the starting column to span within the grid.", "default": "None"}, {"name": "grid_column_end", "type": "str | None", "description": "When used in a grid layout, specifies the ending column to span within the grid.", "default": "None"}, {"name": "margin", "type": "str | float | None", "description": "The margin for all four sides of the element.", "default": "None"}, {"name": "margin_top", "type": "str | float | None", "description": "The margin for the top side of the element.", "default": "None"}, {"name": "margin_bottom", "type": "str | float | None", "description": "The margin for the bottom side of the element.", "default": "None"}, {"name": "margin_start", "type": "str | float | None", "description": "The margin for the logical start side of the element, depending on layout direction.", "default": "None"}, {"name": "margin_end", "type": "str | float | None", "description": "The margin for the logical end side of the element, depending on layout direction.", "default": "None"}, {"name": "margin_x", "type": "str | float | None", "description": "The margin for the left and right sides of the element.", "default": "None"}, {"name": "margin_y", "type": "str | float | None", "description": "The margin for the top and bottom sides 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 top position of the element.", "default": "None"}, {"name": "bottom", "type": "str | float | None", "description": "The bottom position of the element.", "default": "None"}, {"name": "left", "type": "str | float | None", "description": "The left position of the element.", "default": "None"}, {"name": "right", "type": "str | float | None", "description": "The right position of the element.", "default": "None"}, {"name": "start", "type": "str | float | None", "description": "The logical start position of the element, depending on layout direction.", "default": "None"}, {"name": "end", "type": "str | float | None", "description": "The logical end position of the element, depending on layout direction.", "default": "None"}, {"name": "z_index", "type": "int | None", "description": "The stacking order for the element", "default": "None"}, {"name": "is_hidden", "type": "bool | None", "description": "Hides the element.", "default": "None"}, {"name": "id", "type": "str | None", "description": "The unique identifier of the element.", "default": "None"}, {"name": "aria_label", "type": "str | None", "description": "Defines a string value that labels the current element.", "default": "None"}, {"name": "aria_labelledby", "type": "str | None", "description": "Identifies the element (or elements) that labels the current element.", "default": "None"}, {"name": "aria_describedby", "type": "str | None", "description": "Identifies the element (or elements) that describes the object.", "default": "None"}, {"name": "aria_details", "type": "str | None", "description": "Identifies the element (or elements) that provide a detailed, extended description for the object.", "default": "None"}, {"name": "UNSAFE_class_name", "type": "str | None", "description": "Set the CSS className for the element. Only use as a last resort. Use style props instead.", "default": "None"}, {"name": "UNSAFE_style", "type": "Dict[str, Any] | None", "description": "Set the inline style for the element. Only use as a last resort. Use style props instead.", "default": "None"}, {"name": "key", "type": "str | None", "description": "A unique identifier used by React to render elements in a list.", "default": "None"}]}} />

## Item Table Source API reference

An item table source wraps a Table or PartitionedTable to provide additional information for
creating complex items from a table.
A PartitionedTable is only supported if the component itself supports a PartitionedTable as a child.
A PartitionedTable passed here will lead to the same behavior as passing
the PartitionedTable directly to a component, such as creating sections from the partitions in the case of a Picker.

**Returns:** `ItemTableSource` The item table source to pass as a child to a component that supports it.

<ParamTable param={{"module_name": "deephaven.ui.", "name": "item_table_source", "parameters": [{"name": "table", "type": "Table | PartitionedTable", "description": "The table to use as the source of items."}, {"name": "key_column", "type": "str | None", "description": "The column of values to use as item keys. Defaults to the first column.", "default": "None"}, {"name": "label_column", "type": "str | None", "description": "The column of values to display as primary text. Defaults to the key_column value.", "default": "None"}, {"name": "description_column", "type": "str | None", "description": "The column of values to display as descriptions.", "default": "None"}, {"name": "icon_column", "type": "str | None", "description": "The column of values to map to icons.", "default": "None"}, {"name": "title_column", "type": "str | None", "description": "Only valid if table is of type PartitionedTable. The column of values to display as section names. Should be the same for all values in the constituent Table. If not specified, the section titles will be created from the key_columns of the PartitionedTable.", "default": "None"}, {"name": "actions", "type": "Element | None", "description": "The action group or menus to render for all elements within the component, if supported.", "default": "None"}, {"name": "key", "type": "str | None", "description": "A unique identifier used by React to render elements in a list.", "default": "None"}]}} />
