# Tabs

Tabs organize related content into sections within panels, allowing users to navigate between them.

## Example

```python
from deephaven import ui, empty_table

my_tabs_basic = ui.tabs(
    ui.tab("Hello World!", title="Tab 1"),
    ui.tab(
        ui.flex(
            "Hello World with table!",
            empty_table(10).update("I=i"),
        ),
        title="Tab 2",
    ),
)
```

## UI Recommendations

1. Use tabs to organize sections of equal importance. Avoid using tabs for content with varying levels of importance.
2. Use a vertical tabs layout when displaying shortcuts to sections of content on a single page.
3. Avoid nesting tabs more than two levels deep, as it can become overly complicated.

## Content

Tabs can be created using `ui.tab`, or using `ui.tab_list` and `ui.tab_panels`, but not the two options combined.

If you want a default tab layout with minimal customization for tab appearance, tabs should be created by passing in `ui.tab` to `ui.tabs`.

Note that the `ui.tab` component can only be used within `ui.tabs`.

```python
from deephaven import ui


my_tabs_tab_content_example = ui.tabs(
    ui.tab("Arma virumque cano, Troiae qui primus ab oris.", title="Founding of Rome"),
    ui.tab("Senatus Populusque Romanus.", title="Monarchy and Republic"),
    ui.tab("Alea jacta est.", title="Empire"),
)
```

For more control over the layout, types, and styling of the tabs, create them with `ui.tab_list` and `ui.tab_panels` with `ui.tabs`.

The `ui.tab_list` specifies the titles of the tabs, while the `ui.tab_panels` specify the content within each of the tab panels.

When specifying tabs using `ui.tab_list` and `ui.tab_panels`, keys must be provided that match each of the respective tabs.

```python
from deephaven import ui


my_tabs_list_panels_content_example = ui.tabs(
    ui.tab_list(ui.item("Tab 1", key="Key 1"), ui.item("Tab 2", key="Key 2")),
    ui.tab_panels(
        ui.item(
            ui.calendar(
                aria_label="Calendar (uncontrolled)",
                default_value="2020-02-03",
            ),
            key="Key 1",
        ),
        ui.item(
            ui.radio_group(
                ui.radio("Yes", value="Yes"),
                ui.radio("No", value="No"),
                label="Is vanilla the best flavor of ice cream?",
            ),
            key="Key 2",
        ),
        flex_grow=1,
        position="relative",
    ),
    flex_grow=1,
    margin_bottom="size-400",
)
```

Note that both the `ui.tab_list` and `ui.tab_panels` components can also only be used within `ui.tabs`.

## Selection

With tabs, the `default_selected_key` or `selected_key` props can be set to have a selected tab.

```python
from deephaven import ui


@ui.component
def ui_tabs_selected_key_examples():
    selected_tab, set_selected_tab = ui.use_state("Tab 1")
    return [
        "Pick a tab (uncontrolled)",
        ui.tabs(
            ui.tab(
                "There is no prior chat history with John Doe.",
                title="John Doe",
                key="Tab 1",
            ),
            ui.tab(
                "There is no prior chat history with Jane Doe.",
                title="Jane Doe",
                key="Tab 2",
            ),
            ui.tab(
                "There is no prior chat history with Joe Bloggs.",
                title="Joe Bloggs",
                key="Tab 3",
            ),
            default_selected_key="Tab 2",
        ),
        f"Pick a tab (controlled), selected tab: {selected_tab}",
        ui.tabs(
            ui.tab(
                "There is no prior chat history with John Doe.",
                title="John Doe",
                key="Tab 1",
            ),
            ui.tab(
                "There is no prior chat history with Jane Doe.",
                title="Jane Doe",
                key="Tab 2",
            ),
            ui.tab(
                "There is no prior chat history with Joe Bloggs.",
                title="Joe Bloggs",
                key="Tab 3",
            ),
            selected_key=selected_tab,
            on_selection_change=set_selected_tab,
        ),
    ]


my_tabs_selected_key_examples = ui_tabs_selected_key_examples()
```

## Events

The `on_change` property is triggered whenever the currently selected tab changes.

```python
from deephaven import ui


@ui.component
def ui_tabs_on_change_example():
    selected_tab, set_selected_tab = ui.use_state("Tab 1")

    def get_background_color(tab):
        if tab == "Tab 1":
            return "celery-500"
        elif tab == "Tab 2":
            return "fuchsia-500"
        elif tab == "Tab 3":
            return "blue-500"
        else:
            return "gray-200"

    return [
        ui.view(
            ui.tabs(
                ui.tab(
                    "There is no prior chat history with John Doe.",
                    title="John Doe",
                    key="Tab 1",
                ),
                ui.tab(
                    "There is no prior chat history with Jane Doe.",
                    title="Jane Doe",
                    key="Tab 2",
                ),
                ui.tab(
                    "There is no prior chat history with Joe Bloggs.",
                    title="Joe Bloggs",
                    key="Tab 3",
                ),
                selected_key=selected_tab,
                on_selection_change=set_selected_tab,
            ),
            background_color=get_background_color(selected_tab),
            flex="auto",
            width="100%",
        ),
        ui.text(f"You have selected: {selected_tab}"),
    ]


my_tabs_on_change_example = ui_tabs_on_change_example()
```

## Keyboard activation

By default, pressing the arrow keys while currently focused on a tab will automatically switch selection to the adjacent tab in that key’s direction.

To prevent this automatic selection change, the `keyboard_activation` prop can be set to “manual”.

```python
from deephaven import ui


my_tabs_keyboard_activation_example = ui.tabs(
    ui.tab("Arma virumque cano, Troiae qui primus ab oris.", title="Founding of Rome"),
    ui.tab("Senatus Populusque Romanus.", title="Monarchy and Republic"),
    ui.tab("Alea jacta est.", title="Empire"),
    keyboard_activation="manual",
)
```

## Density

By default, the density of the tab list is “compact”. To change this, the `density` prop can be set to “regular”.

```python
from deephaven import ui


@ui.component
def ui_tabs_density_examples():
    return [
        ui.tabs(
            ui.tab("There is no prior chat history with John Doe.", title="John Doe"),
            ui.tab("There is no prior chat history with Jane Doe.", title="Jane Doe"),
            ui.tab(
                "There is no prior chat history with Joe Bloggs.", title="Joe Bloggs"
            ),
            density="regular",
        ),
    ]


my_tabs_density_examples = ui_tabs_density_examples()
```

## Quiet State

The `is_quiet` prop makes tabs “quiet” by removing the line separating the tab titles and panel contents. This can be useful when the tabs should not distract users from surrounding content.

```python
from deephaven import ui


my_tabs_is_quiet_example = ui.tabs(
    ui.tab("There is no prior chat history with John Doe.", title="John Doe"),
    ui.tab("There is no prior chat history with Jane Doe.", title="Jane Doe"),
    ui.tab("There is no prior chat history with Joe Bloggs.", title="Joe Bloggs"),
    is_quiet=True,
)
```

## Disabled state

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

```python
from deephaven import ui


my_tabs_is_disabled_example = ui.tabs(
    ui.tab("There is no prior chat history with John Doe.", title="John Doe"),
    ui.tab("There is no prior chat history with Jane Doe.", title="Jane Doe"),
    ui.tab("There is no prior chat history with Joe Bloggs.", title="Joe Bloggs"),
    is_disabled=True,
)
```

## Orientation

By default, tabs are horizontally oriented. To change the tabs’ orientation, set the `orientation` prop to “vertical”.

```python
from deephaven import ui


@ui.component
def ui_tabs_orientation_examples():
    return [
        ui.tabs(
            ui.tab("There is no prior chat history with John Doe.", title="John Doe"),
            ui.tab("There is no prior chat history with Jane Doe.", title="Jane Doe"),
            ui.tab(
                "There is no prior chat history with Joe Bloggs.", title="Joe Bloggs"
            ),
            orientation="vertical",
        ),
        ui.tabs(
            ui.tab("There is no prior chat history with John Doe.", title="John Doe"),
            ui.tab("There is no prior chat history with Jane Doe.", title="Jane Doe"),
            ui.tab(
                "There is no prior chat history with Joe Bloggs.", title="Joe Bloggs"
            ),
        ),
    ]


my_tabs_orientation_examples = ui_tabs_orientation_examples()
```

## Overflow behaviour

If there isn’t enough horizontal space to render all tabs on a single line, the component will automatically collapse all tabs into a Picker.

Note that this only occurs when tabs are horizontally oriented; when tabs are vertically oriented, the list continues to extend downwards.

```python
from deephaven import ui


@ui.component
def ui_tabs_overflow_example():
    return [
        ui.view(
            ui.tabs(
                ui.tab(
                    "There is no prior chat history with John Doe.", title="John Doe"
                ),
                ui.tab(
                    "There is no prior chat history with Jane Doe.", title="Jane Doe"
                ),
                ui.tab(
                    "There is no prior chat history with Joe Bloggs.",
                    title="Joe Bloggs",
                ),
            ),
            width="80px",
        )
    ]


my_tabs_overflow_example = ui_tabs_overflow_example()
```

## Emphasized

The `is_emphasized` prop makes the line underneath the selected tab the user’s accent color, adding a visual prominence to the selection.

```python
from deephaven import ui


my_tabs_is_emphasized_example = ui.tabs(
    ui.tab("There is no prior chat history with John Doe.", title="John Doe"),
    ui.tab("There is no prior chat history with Jane Doe.", title="Jane Doe"),
    ui.tab("There is no prior chat history with Joe Bloggs.", title="Joe Bloggs"),
    is_emphasized=True,
)
```

## API Reference

Python implementation for the Adobe React Spectrum Tabs component.
https://react-spectrum.adobe.com/react-spectrum/Tabs.html

**Returns:** `BaseElement` The rendered tabs component.

<ParamTable param={{"module_name": "deephaven.ui.", "name": "tabs", "parameters": [{"name": "*children", "type": "Any", "description": "The children of the tabs component outline how the tabs will be created, they can be either: ui.tab: A tab item that is a shorthand way to create a tab item. ui.tab_list & ui.tab_panels: A tab list and tab panels allow for more customization when creating tabs."}, {"name": "disabled_keys", "type": "Iterable[str | int | float | bool] | None", "description": "The keys of the tabs that are disabled. These tabs cannot be selected, focused, or otherwise interacted with.", "default": "None"}, {"name": "is_disabled", "type": "bool | None", "description": "Whether the Tabs are disabled.", "default": "None"}, {"name": "is_quiet", "type": "bool | None", "description": "Whether the tabs are displayed in a quiet style.", "default": "None"}, {"name": "is_emphasized", "type": "bool | None", "description": "Whether the tabs are displayed in an emphasized style.", "default": "None"}, {"name": "density", "type": "Literal['compact', 'regular'] | None", "description": "The amount of space between the tabs.", "default": "'compact'"}, {"name": "keyboard_activation", "type": "Literal['automatic', 'manual'] | None", "description": "Whether tabs are activated automatically on focus or manually.", "default": "'automatic'"}, {"name": "orientation", "type": "Literal['horizontal', 'vertical'] | None", "description": "The orientation of the tabs.", "default": "'horizontal'"}, {"name": "disallow_empty_selection", "type": "bool | None", "description": "Whether the collection allows empty selection.", "default": "None"}, {"name": "selected_key", "type": "str | int | float | bool | None", "description": "The currently selected key in the collection (controlled).", "default": "None"}, {"name": "default_selected_key", "type": "str | int | float | bool | None", "description": "The initial selected key in the collection (uncontrolled).", "default": "None"}, {"name": "on_selection_change", "type": "Callable[[str | int | float | bool], None] | None", "description": "Callback for when the selected key 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": "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": "1"}, {"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, 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 position.", "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_labelled_by", "type": "str | None", "description": "Identifies the element (or elements) that labels the current element.", "default": "None"}, {"name": "aria_described_by", "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"}]}} />
