Skip to content

Accordion

Accordion stacks collapsible panels so related copy stays compact until the reader opens a header. It is the NiceGUI surface for Bootstrap 5's accordion (accordion / accordion-item). Use it for FAQs, settings groups, and any long page where several sections should share one vertical footprint.

Basic usage

Nest AccordionItem children inside Accordion. Pass title for the clickable header and put the panel body in the item (a with-block or child elements). Set item_id when you need to address a panel from Python. The snippets below are the same sources the demo service runs.

accordion_simple example

def demo() -> None:
    with bs.scope(), bs.accordion():
        with bs.accordion_item(title="Item 1"):
            ui.label("This is the content of the first section")
            bs.button("Click here")
        with bs.accordion_item(title="Item 2"):
            ui.label("This is the content of the second section")
            bs.button("Don't click me!", color="danger")
        with bs.accordion_item(title="Item 3"):
            ui.label("This is the content of the third section")

The snake_case names accordion and accordion_item are aliases for Accordion and AccordionItem.

Start collapsed

Pass start_collapsed=True to close every panel on first render. Without it the first item is open by default.

accordion_collapsed example

def demo() -> None:
    with bs.scope(), bs.accordion(start_collapsed=True):
        with bs.accordion_item(title="Item 1"):
            ui.label("This is the content of the first section")
        with bs.accordion_item(title="Item 2"):
            ui.label("This is the content of the second section")
        with bs.accordion_item(title="Item 3"):
            ui.label("This is the content of the third section")

Flush

flush=True drops the outer border and radius so the stack can sit flush against a parent edge.

accordion_flush example

def demo() -> None:
    with bs.scope(), bs.accordion(flush=True):
        with bs.accordion_item(title="Item 1"):
            ui.label("This is the content of the first section")
        with bs.accordion_item(title="Item 2"):
            ui.label("This is the content of the second section")
        with bs.accordion_item(title="Item 3"):
            ui.label("This is the content of the third section")

Callbacks

Each item can be assigned a stable item_id, which the active_item value and on_change use to say which panel is open. Items without an explicit id are labelled item-0, item-1, and so on.

accordion_callback example

def demo() -> None:
    with bs.scope():
        selected = ui.label("Item selected: item-1")

        def on_change(event: object) -> None:
            value = getattr(event, "value", event)
            selected.set_text(f"Item selected: {value}")

        with bs.accordion(active_item="item-1", on_change=on_change):
            with bs.accordion_item(title="Item 1", item_id="item-1"):
                ui.label("This is the content of the first section")
            with bs.accordion_item(title="Item 2", item_id="item-2"):
                ui.label("This is the content of the second section")
            with bs.accordion_item(title="Item 3", item_id="item-3"):
                ui.label("This is the content of the third section")

Always open

Set always_open=True to allow several panels to stay open together.

accordion_always_open example

def demo() -> None:
    with bs.scope(), bs.accordion(always_open=True):
        with bs.accordion_item(title="Item one"):
            ui.label("First panel.")
        with bs.accordion_item(title="Item two"):
            ui.label("Second panel.")
        with bs.accordion_item(title="Item three"):
            ui.label("Third panel.")

With always_open=True, active_item is a list of ids.

accordion_always_open_callback example

def demo() -> None:
    with bs.scope():
        selected = ui.label("Item(s) selected: []")

        def on_change(event: object) -> None:
            value = getattr(event, "value", event)
            selected.set_text(f"Item(s) selected: {value}")

        with bs.accordion(always_open=True, on_change=on_change):
            with bs.accordion_item(title="Item 1: item-0"):
                ui.label("This is the content of the first section.")
            with bs.accordion_item(title="Item 2: item-1"):
                ui.label("This is the content of the second section.")
            with bs.accordion_item(title="Item 3: item-2"):
                ui.label("This is the content of the third section.")

Argument reference

Property Type Default DBC 2.0.4 name Support (native) Support (compat)
children a list of or a singular dash component, string or number None children supported supported
id string None id supported supported
active_item string | list of strings None active_item supported supported
always_open boolean False always_open supported supported
start_collapsed boolean False start_collapsed supported supported
flush boolean None flush supported supported
style unknown None style supported supported
class_name string None className supported supported
persistence boolean | string | number None persistence unsupported unsupported
persisted_props list of a value equal to: 'active_item's None persisted_props unsupported unsupported
persistence_type a value equal to: 'local', 'session', 'memory' None persistence_type unsupported unsupported
key string None key unsupported unsupported
class_name string None className supported supported

Notes

AccordionItem also accepts title_class_name for the header control, plus the shared layout props class_name, style, and id. persist defaults to "off". Give each item a stable item_id if you drive active_item from Python. Header click counts from Dash are not a separate accordion prop here; interactive wiring follows NiceGUI handlers. See the compatibility page for how Dash-style props are adapted.