express.ui.toolbar

express.ui.toolbar(*args, align='right', gap=None, width=None)

Create a toolbar container.

A toolbar which can contain buttons, inputs, and other UI elements in a small form suitable for inclusion in card headers, footers, and other small places.

Parameters

*args : TagChild = ()

UI elements for the toolbar.

align : Literal[‘right’, ‘left’] = 'right'

Determines if toolbar should be aligned to the "right" or "left".

gap : Optional[CssUnit] = None

A CSS length unit defining the gap (i.e., spacing) between elements in the toolbar. Defaults to 0 (no gap).

width : Optional[CssUnit] = None

CSS width of the toolbar. Defaults to None, which will automatically set width: 100% when the toolbar is a direct child of a label element (e.g., when used in input labels). For toolbar_spacer, to push elements effectively, the toolbar needs width="100%" to expand and create space. Set this explicitly if you need to control the width in other contexts.

Returns

: Tag

A UI element

See Also

Examples

from shiny import ui
from faicons import icon_svg

# Basic toolbar with buttons
ui.toolbar(
    ui.toolbar_input_button(id="save", label="Save"),
    ui.toolbar_input_button(
        id="edit",
        label="Edit",
        icon=icon_svg("gear")
    )
    align="right"
)

Examples

#| standalone: true
#| components: [editor, viewer]
#| layout: vertical
#| viewerHeight: 400

## file: app.py
from faicons import icon_svg

from shiny import reactive
from shiny.express import input, render, ui

ui.h2("Toolbar Kitchen Sink Example")
ui.p("Comprehensive examples of toolbar usage patterns")

with ui.layout_columns(col_widths=[6, 6]):
    with ui.card():
        with ui.card_header():
            "Toolbar in header & label"
            with ui.toolbar(align="right"):
                ui.toolbar_input_button(
                    "btn_save",
                    label="Save",
                    icon=icon_svg("floppy-disk"),
                    tooltip="Save Document",
                )
                ui.toolbar_divider()
                ui.toolbar_input_select(
                    "format",
                    label="Format",
                    choices={"md": "Markdown", "txt": "Plain Text", "html": "HTML"},
                    selected="md",
                    icon=icon_svg("file-code"),
                )

        with ui.card_body():
            ui.input_text_area(
                "content",
                label=ui.toolbar(
                    ui.toolbar_input_button(
                        "btn_bold",
                        label="Bold",
                        icon=icon_svg("bold"),
                    ),
                    ui.toolbar_input_button(
                        "btn_italic",
                        label="Italic",
                        icon=icon_svg("italic"),
                    ),
                    ui.toolbar_input_button(
                        "btn_code",
                        label="Code",
                        icon=icon_svg("code"),
                    ),
                    align="right",
                ),
                placeholder="Type your content here...",
                rows=8,
            )

            @render.text
            def output_card1():
                save_clicks = input.btn_save()
                format_val = input.format()
                bold_clicks = input.btn_bold()
                italic_clicks = input.btn_italic()
                code_clicks = input.btn_code()
                return f"Save: {save_clicks} | Format: {format_val} | Bold: {bold_clicks}, Italic: {italic_clicks}, Code: {code_clicks}"

    with ui.card():
        with ui.card_header():
            "Toolbar in header & input label"
            with ui.toolbar(align="right"):
                ui.toolbar_input_select(
                    "view_mode",
                    label="View",
                    choices={
                        "grid": "Grid",
                        "list": "List",
                        "slideshow": "Slideshow",
                    },
                    selected="grid",
                    icon=icon_svg("images"),
                )
                ui.toolbar_divider()
                ui.toolbar_input_button(
                    "btn_filter",
                    label="Filter",
                    icon=icon_svg("filter"),
                )
                ui.toolbar_input_button(
                    "btn_sort",
                    label="Sort",
                    icon=icon_svg("arrow-down-a-z"),
                )

        with ui.card_body():
            ui.input_numeric(
                "quantity",
                label=ui.toolbar(
                    "Adjust Quantity:",
                    ui.toolbar_spacer(),
                    ui.toolbar_input_button(
                        "btn_preset_10",
                        label="10",
                        show_label=True,
                        tooltip="Set to 10",
                    ),
                    ui.toolbar_input_button(
                        "btn_preset_50",
                        label="50",
                        show_label=True,
                        tooltip="Set to 50",
                    ),
                    ui.toolbar_input_button(
                        "btn_preset_100",
                        label="100",
                        show_label=True,
                        tooltip="Set to 100",
                    ),
                    ui.toolbar_divider(),
                    ui.toolbar_input_button(
                        "btn_reset",
                        label="Reset",
                        icon=icon_svg("rotate-left"),
                        tooltip="Reset to 1",
                    ),
                    align="right",
                ),
                value=1,
                min=1,
                max=1000,
            )

            @render.text
            def output_card3():
                view_mode = input.view_mode()
                filter_clicks = input.btn_filter()
                sort_clicks = input.btn_sort()
                quantity = input.quantity()
                return f"View: {view_mode} | Quantity: {quantity} | Filter: {filter_clicks}, Sort: {sort_clicks}"


with ui.card():
    with ui.card_header():
        "Toolbar in Text Input Submit Area: Message Composer"
        with ui.toolbar(align="right"):
            ui.toolbar_input_button(
                "btn_new",
                label="New Chat",
                icon=icon_svg("plus"),
                show_label=True,
            )
            ui.toolbar_spacer()
            ui.toolbar_input_select(
                "recipient",
                label="To",
                choices={
                    "team": "Team",
                    "manager": "Manager",
                    "support": "Support",
                },
                selected="team",
                show_label=True,
            )

    with ui.card_body():
        with ui.layout_columns(col_widths=[6, 6]):
            ui.input_submit_textarea(
                "message",
                label="Message",
                placeholder="Compose your message...",
                rows=6,
                toolbar=ui.toolbar(
                    ui.toolbar_input_select(
                        "priority",
                        label="Priority",
                        choices={"low": "Low", "medium": "Medium", "high": "High"},
                        selected="medium",
                        icon=icon_svg("flag"),
                    ),
                    ui.toolbar_divider(),
                    ui.toolbar_input_button(
                        "btn_attach",
                        label="Attach",
                        icon=icon_svg("paperclip"),
                    ),
                    ui.toolbar_input_button(
                        "btn_emoji",
                        label="Emoji",
                        icon=icon_svg("face-smile"),
                    ),
                    align="right",
                ),
            )
            with ui.div():
                ui.h5("Sent Messages")

                @render.ui
                def output_card2():
                    msg_list = messages.get()
                    if not msg_list:
                        return ui.p("No messages sent yet.", style="color: #888;")

                    items = []
                    for _, msg in enumerate(reversed(msg_list), 1):
                        items.append(
                            ui.div(
                                ui.strong(
                                    f"To: {msg['to']} ({msg['priority']} priority)"
                                ),
                                ui.br(),
                                ui.span(msg["text"]),
                                style="padding: 8px; margin-bottom: 8px; border: 1px solid #ddd; border-radius: 4px; display: block;",
                            )
                        )
                    return ui.div(*items)


# Update save button icon and tooltip after click
@reactive.effect
@reactive.event(input.btn_save)
def _():
    ui.update_toolbar_input_button(
        "btn_save",
        icon=icon_svg("circle-check"),
    )
    ui.update_tooltip("btn_save_tooltip", "Saved successfully!")


# Numeric input preset buttons
@reactive.effect
@reactive.event(input.btn_preset_10)
def _():
    ui.update_numeric("quantity", value=10)


@reactive.effect
@reactive.event(input.btn_preset_50)
def _():
    ui.update_numeric("quantity", value=50)


@reactive.effect
@reactive.event(input.btn_preset_100)
def _():
    ui.update_numeric("quantity", value=100)


@reactive.effect
@reactive.event(input.btn_reset)
def _():
    ui.update_numeric("quantity", value=1)


# Message handling
messages = reactive.value([])


@reactive.effect
@reactive.event(input.message)
def _():
    message_text = input.message()
    recipient = input.recipient()
    priority = input.priority()
    if message_text and message_text.strip():
        current_messages = list(messages.get())
        current_messages.append(
            {"text": message_text, "to": recipient, "priority": priority}
        )
        messages.set(current_messages)


@reactive.effect
@reactive.event(input.btn_new)
def _():
    messages.set([])
    ui.update_text_area("message", value="")