# Dialog

Dialogs are windows containing contextual information, tasks, or workflows that appear over the user interface. Depending on the kind of dialog, further interactions may be blocked until the dialog is acknowledged.

## Example

```python
from deephaven import ui


@ui.component
def dialog_example():
    is_open, set_open = ui.use_boolean()
    return ui.dialog_trigger(
        ui.action_button("Check connectivity", on_press=set_open.on),
        ui.dialog(
            ui.heading("Internet Speed Test"),
            ui.content("Start speed test?"),
            ui.button_group(
                ui.button("Cancel", variant="secondary", on_press=set_open.off),
                ui.button("Confirm", variant="accent", on_press=set_open.off),
            ),
        ),
        is_open=is_open,
    )


my_dialog_example = dialog_example()
```

## Content

The content can be populated by providing the following components to your `dialog` as children:

- `header` (optional)
- `heading` (title, required)
- `divider` (optional)
- `content` (body, required)
- `button_group` (optional)
- `footer` (optional)

### Examples

A typical `dialog` with a title, contents, and action buttons can be created like so:

```python
from deephaven import ui


@ui.component
def dialog_example1():
    is_open, set_open = ui.use_boolean()
    return ui.dialog_trigger(
        ui.action_button("Publish", on_press=set_open.on),
        ui.dialog(
            ui.heading("Publish 3 pages"),
            ui.content("Confirm publish?"),
            ui.button_group(
                ui.button("Cancel", variant="secondary", on_press=set_open.off),
                ui.button(
                    "Confirm", variant="accent", on_press=set_open.off, auto_focus=True
                ),
            ),
        ),
        is_open=is_open,
    )


my_dialog_example1 = dialog_example1()
```

A dismissable `dialog` forgoes its `button_group` in favor of rendering a close button at the top right of the `dialog`.

```python
from deephaven import ui

my_dialog_example2 = ui.dialog_trigger(
    ui.action_button("Status"),
    ui.dialog(ui.heading("Status"), ui.content("Printer Status: Connected")),
    is_dismissable=True,
)
```

It is important to note that the `heading`, `header`, `content`, and `footer` content elements accept any renderable node, not just strings. This allows you to create `dialogs` for more complex workflows, such as including a form for the user to fill out or adding confirmation checkboxes.

```python
from deephaven import ui


@ui.component
def dialog_example3():
    is_open, set_open = ui.use_boolean()
    return ui.dialog_trigger(
        ui.action_button("Register", on_press=set_open.on),
        ui.dialog(
            ui.heading(
                ui.flex(
                    ui.text("Register for newsletter"),
                    align_items="center",
                    gap="size-100",
                )
            ),
            ui.content(
                ui.form(
                    ui.text_field(label="First Name", auto_focus=True),
                    ui.text_field(label="Last Name"),
                    ui.text_field(label="Street Address"),
                    ui.text_field(label="City"),
                    ui.checkbox(
                        "I want to receive updates for exclusive offers in my area."
                    ),
                )
            ),
            ui.button_group(
                ui.button("Cancel", variant="secondary", on_press=set_open.off),
                ui.button("Register", variant="accent", on_press=set_open.off),
            ),
        ),
        is_open=is_open,
    )


my_dialog_example3 = dialog_example3()
```

## Events

For dialogs, user defined callbacks should be chained with the close function in the `on_press` handler of the dialog’s action buttons. The following example prints if the dialog’s save or cancel button is clicked.

```python
from deephaven import ui


@ui.component
def print_example():
    is_open, set_open = ui.use_boolean()

    def print_save():
        set_open.off()
        print("Profile saved!")

    def print_cancel():
        set_open.off()
        print("Provfile not saved!")

    return ui.dialog_trigger(
        ui.action_button("Set Profile", on_press=set_open.on),
        ui.dialog(
            ui.heading("Profile"),
            ui.content(
                ui.form(ui.text_field(label="Name"), ui.checkbox("Make private"))
            ),
            ui.button_group(
                ui.button("Cancel", variant="secondary", on_press=print_cancel),
                ui.button("Confirm", variant="accent", on_press=print_save),
            ),
        ),
        is_open=is_open,
    )


my_print_example = print_example()
```

### Dismissable dialogs

Dismissable dialogs support an optional `on_dismiss` prop that is triggered whenever the dialog’s close button is clicked. Like non-dismissable dialogs, you must chain the close function with whatever callback you provide as `onDismiss`. If this event callback is not needed, the dismissable dialog will behave normally without passing this callback through.

```python
from deephaven import ui


@ui.component
def dismissable_callback():
    is_open, set_open = ui.use_boolean()

    def print_dismiss():
        set_open.off()
        print("Dialog dismissed.")

    return ui.dialog_trigger(
        ui.action_button("Info", on_press=set_open.on),
        ui.dialog(
            ui.heading("Version Info"),
            ui.content("Version 1.0.0, Copyright 2020"),
            on_dismiss=print_dismiss,
        ),
        is_open=is_open,
        is_dismissable=True,
    )


my_dismissable_callback = dismissable_callback()
```

## Visual options

### Dialog types

Dialogs can be rendered as modals, popovers, or trays. See the [`dialog_trigger`](dialog_trigger.md) docs for more information.

```python
from deephaven import ui


my_modal = ui.dialog_trigger(
    ui.action_button(
        "Trigger Modal",
    ),
    ui.dialog(
        ui.heading("Modal"),
        ui.content("This is a modal."),
    ),
    is_dismissable=True,
    type="modal",
)

my_popover = ui.dialog_trigger(
    ui.action_button(
        "Trigger Popover",
    ),
    ui.dialog(
        ui.heading("Popover"),
        ui.content("This is a popover."),
    ),
    type="popover",
)

my_tray = ui.dialog_trigger(
    ui.action_button(
        "Trigger Tray",
    ),
    ui.dialog(
        ui.heading("Tray"),
        ui.content("This is a tray."),
    ),
    type="tray",
)
```

### Size

Only `modal` type dialogs support a user defined size prop. Note that the `fullscreen` and `fullscreenTakeover` sizes require the `dialog_trigger` `type` prop to be set to `fullscreen` or `fullscreenTakeover` respectively for container sizing considerations.

```python
from deephaven import ui


@ui.component
def small_example():
    is_open, set_open = ui.use_boolean()
    return ui.dialog_trigger(
        ui.action_button("Small", on_press=set_open.on),
        ui.dialog(
            ui.heading("Profile"),
            ui.content(
                ui.form(ui.text_field(label="Name"), ui.checkbox("Make private"))
            ),
            ui.button_group(
                ui.button("Cancel", variant="secondary", on_press=set_open.off),
                ui.button("Confirm", variant="accent", on_press=set_open.off),
            ),
            size="S",
        ),
        is_open=is_open,
    )


my_small_example = small_example()


@ui.component
def medium_example():
    is_open, set_open = ui.use_boolean()
    return ui.dialog_trigger(
        ui.action_button("Medium", on_press=set_open.on),
        ui.dialog(
            ui.heading("Profile"),
            ui.content(
                ui.form(ui.text_field(label="Name"), ui.checkbox("Make private"))
            ),
            ui.button_group(
                ui.button("Cancel", variant="secondary", on_press=set_open.off),
                ui.button("Confirm", variant="accent", on_press=set_open.off),
            ),
            size="M",
        ),
        is_open=is_open,
    )


my_medium_example = medium_example()


@ui.component
def large_example():
    is_open, set_open = ui.use_boolean()
    return ui.dialog_trigger(
        ui.action_button("Large", on_press=set_open.on),
        ui.dialog(
            ui.heading("Profile"),
            ui.content(
                ui.form(ui.text_field(label="Name"), ui.checkbox("Make private"))
            ),
            ui.button_group(
                ui.button("Cancel", variant="secondary", on_press=set_open.off),
                ui.button("Confirm", variant="accent", on_press=set_open.off),
            ),
            size="L",
        ),
        is_open=is_open,
    )


my_large_example = large_example()
```

## API Reference

A dialog is a window containing contextual information, tasks, or workflows that appear over the user interface.

**Returns:** `Element` The dialog element.

<ParamTable param={{"module_name": "deephaven.ui.", "name": "dialog", "parameters": [{"name": "*children", "type": "Any", "description": "The contents of the Dialog."}, {"name": "size", "type": "Literal['S', 'M', 'L'] | None", "description": "The size of the Dialog. Only applies to \"modal\" type Dialogs.", "default": "None"}, {"name": "is_dismissable", "type": "bool | None", "description": "Whether the Dialog is dismissable.", "default": "None"}, {"name": "on_dismiss", "type": "Callable[[], None] | None", "description": "Handler that is called when the 'x' button of a dismissable Dialog is clicked.", "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": "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_pressed", "type": "Literal['true', 'false'] | bool | Literal['mixed'] | None", "description": "Whether the element is pressed.", "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"}]}} />
