Accordion#

A list of collapsible sections, optionally limited to one open at a time. Each section is a collapsible panel added via add().

Accordion — light theme Accordion — dark theme

Usage#

An accordion stacks collapsible sections inline, each added with add(title). Reach for it to let users expand sections in place within a scrolling page; use Tabs when the views should swap in a fixed area instead.

Basic accordion#

add(title) returns an AccordionSection context manager. Place child widgets inside it. By default only one section can be open at a time — opening a second one collapses the first.

acc = bs.Accordion()
with acc.add("Introduction", expanded=True):
    bs.Label("First section body.")
with acc.add("Details"):
    bs.Label("Opening this collapses Introduction.")
with acc.add("Summary"):
    bs.Label("Third section.")

Multiple open at once#

allow_multiple=True lets any number of sections be open simultaneously.

acc = bs.Accordion(allow_multiple=True)
with acc.add("Section A", expanded=True):
    bs.Label("A is open.")
with acc.add("Section B", expanded=True):
    bs.Label("B is also open.")

Prevent full collapse#

allow_collapse_all=False keeps at least one section expanded at all times. The first section added is expanded by default.

acc = bs.Accordion(allow_collapse_all=False)
with acc.add("Always one open"):
    bs.Label("Cannot be the last one closed.")

Dividers#

show_separators=True (default) draws a divider line between sections. Set show_separators=False to remove the dividers.

acc = bs.Accordion(show_separators=False)
with acc.add("Alpha", expanded=True):
    bs.Label("Body.")
with acc.add("Beta"):
    bs.Label("Body.")

Border#

show_border=True (default) wraps the entire accordion in a bordered frame. Set show_border=False to render without an outer border.

acc = bs.Accordion(show_border=False)
with acc.add("One", expanded=True):
    bs.Label("No outer border.")
with acc.add("Two"):
    bs.Label("Body.")

Accent#

accent= applies a color token to every section header. Valid values: 'primary', 'secondary', 'info', 'success', 'warning', 'danger', 'default'.

acc = bs.Accordion(accent="primary")
with acc.add("Features", expanded=True):
    bs.Label("Feature list.")
with acc.add("Pricing"):
    bs.Label("Pricing details.")
Accordion accent — light theme Accordion accent — dark theme

Icons#

Pass icon= to add() to display an icon to the left of the section title.

acc = bs.Accordion(accent="primary")
with acc.add("Documents", icon="folder", expanded=True):
    bs.Label("PDF reports, spreadsheets, and presentations.")
with acc.add("Images", icon="image"):
    bs.Label("Photos and exported graphics.")
with acc.add("Music", icon="file-music"):
    bs.Label("Audio files and playlists.")
Accordion icons — light theme Accordion icons — dark theme

Section layout#

Each section body supports the same layout=, gap=, horizontal_items=, and other layout kwargs as a standalone Column.

acc = bs.Accordion()
with acc.add("Form", layout="grid", columns=["auto", 1],
             gap=8, horizontal_items="stretch"):
    bs.Label("Name")
    bs.TextField()
    bs.Label("Email")
    bs.TextField()

Managing sections#

acc = bs.Accordion()
with acc.add("Alpha", expanded=True):
    bs.Label("Body.")

acc.expand("expander_0")     # expand by auto-assigned key
acc.collapse("expander_0")
acc.expand_all()
acc.collapse_all()
acc.keys()                   # tuple of all section keys in order

Events#

on_change() fires whenever any section expands or collapses.

acc = bs.Accordion()

acc.on_change(lambda e: print("section changed"))

# Stream (chainable)
acc.on_change().listen(lambda e: print("changed"))

Widget sizing#

All widgets accept self-placement kwargs via **kwargs. The parent container determines which options apply — Column / Row parents use the layout kwargs below, grid-based parents use grid kwargs.

Column (vertical layout)

Used inside a Column, App, or any other container with a column layout. Children are arranged top-to-bottom, so horizontal aligns each child across the width and grow shares the vertical space. (vertical does not apply — the order of the children sets their top-to-bottom position.)

horizontal

Cross-axis placement of the widget: 'left', 'center', 'right', or 'stretch' to fill the available width.

grow

Claim and fill a share of the leftover vertical space (the layout direction). True or False.

margin

External spacing in pixels. Accepts an integer (equal on all sides), a 2-tuple (horizontal, vertical), or a 4-tuple (left, top, right, bottom).

margin_x

Horizontal external spacing (left and right). Accepts an integer or a 2-tuple (left, right) for asymmetric spacing. Overrides the horizontal component of margin=.

margin_y

Vertical external spacing (top and bottom). Accepts an integer or a 2-tuple (top, bottom) for asymmetric spacing. Overrides the vertical component of margin=.

Row (horizontal layout)

Used inside a Row or any other container with a row layout. Children are arranged left-to-right, so vertical aligns each child across the height and grow shares the horizontal space. (horizontal does not apply — the order of the children sets their left-to-right position.)

vertical

Cross-axis placement of the widget: 'top', 'center', 'bottom', or 'stretch' to fill the available height.

grow

Claim and fill a share of the leftover horizontal space (the layout direction). True or False.

margin

External spacing in pixels. Accepts an integer (equal on all sides), a 2-tuple (horizontal, vertical), or a 4-tuple (left, top, right, bottom).

margin_x

Horizontal external spacing (left and right). Accepts an integer or a 2-tuple (left, right) for asymmetric spacing. Overrides the horizontal component of margin=.

margin_y

Vertical external spacing (top and bottom). Accepts an integer or a 2-tuple (top, bottom) for asymmetric spacing. Overrides the vertical component of margin=.

Grid

Used inside a Grid container.

row / column

Zero-based row and column indices.

rowspan / columnspan

Number of rows or columns to span.

horizontal

Horizontal placement within the grid cell: 'left', 'center', 'right', or 'stretch' to fill the cell width.

vertical

Vertical placement within the grid cell: 'top', 'center', 'bottom', or 'stretch' to fill the cell height.

margin

External spacing in pixels. Accepts an integer, a 2-tuple (horizontal, vertical), or a 4-tuple (left, top, right, bottom).

margin_x

Horizontal external spacing. Accepts an integer or (left, right).

margin_y

Vertical external spacing. Accepts an integer or (top, bottom).

See also#

Card and GroupBox are non-collapsible containers.

API#

The complete reference for Accordion and its AccordionSection handles lives on the Widgets API page. At a glance:

Accordion

A list of collapsible sections, optionally limited to one open at a time.

AccordionSection

A handle for one accordion section — both a layout context and a live controller.

Full Example#

 1
 2with bs.App(title="Accordion", size=(680, 950), padding=20, gap=16) as app:
 3
 4    # ── Single open (default) ─────────────────────────────────────────────────
 5    with bs.Column(gap=0, horizontal="stretch"):
 6        bs.Label("Single open (default)", font="heading-md")
 7
 8    acc = bs.Accordion()
 9    with acc.add("Introduction", expanded=True):
10        bs.Label("Only one section can be open at a time.")
11        bs.Label("Opening another collapses this one.")
12    with acc.add("Details"):
13        bs.Label("Opening this collapses Introduction.")
14    with acc.add("Summary"):
15        bs.Label("Third section body.")
16
17    # ── Multiple open ─────────────────────────────────────────────────────────
18    with bs.Column(gap=0, horizontal="stretch"):
19        bs.Label("allow_multiple=True", font="heading-md")
20
21    acc2 = bs.Accordion(allow_multiple=True)
22    with acc2.add("Section A", expanded=True):
23        bs.Label("Multiple sections can be open simultaneously.")
24    with acc2.add("Section B", expanded=True):
25        bs.Label("A and B both start expanded.")
26    with acc2.add("Section C"):
27        bs.Label("C starts collapsed.")
28
29    # ── Accent ────────────────────────────────────────────────────────────────
30    with bs.Column(gap=0, horizontal="stretch"):
31        bs.Label("accent=", font="heading-md")
32
33    with bs.Accordion(accent='primary').add('Primary', expanded=True):
34        bs.Label("All headers share the same accent selection color.")
35
36    # ── Icons ────────────────────────────────────────────────────────────────
37    with bs.Column(gap=0, horizontal="stretch"):
38        bs.Label("icon=", font="heading-md")
39
40    bicon = bs.Accordion(accent='info')
41    with bicon.add('Documents', icon='folder'):
42        bs.Label("Documents here")
43    with bicon.add('Images', icon='image'):
44        bs.Label("Images here")
45    with bicon.add('Music', icon='file-music'):
46        bs.Label("Music here")
47
48app.run()