Skip to content

ExpansionTile

A single-line ListTile with an expansion arrow icon that expands or collapses the tile to reveal or hide its controls.

ft.ExpansionTile(
    width=400,
    title="Account",
    subtitle="Manage profile and security",
    expanded=True,
    controls=[
        ft.ListTile(title=ft.Text("Profile")),
        ft.ListTile(title=ft.Text("Security")),
    ],
)

ExpansionTile

Basic ExpansionTile

Inherits: LayoutControl, AdaptiveControl

Properties

Events

Examples#

Live example

Basic Example#

import flet as ft


def main(page: ft.Page):
    page.theme_mode = ft.ThemeMode.LIGHT
    page.spacing = 0
    page.padding = 0

    def handle_tile_change(e: ft.Event[ft.ExpansionTile]):
        page.show_dialog(
            ft.SnackBar(
                duration=1000,
                content=ft.Text(
                    value=f"ExpansionTile was {'expanded' if e.data == 'true' else 'collapsed'}"
                ),
            )
        )
        if e.control.trailing:
            e.control.trailing.name = (
                ft.Icons.ARROW_DROP_DOWN
                if e.control.trailing.name == ft.Icons.ARROW_DROP_DOWN_CIRCLE
                else ft.Icons.ARROW_DROP_DOWN_CIRCLE
            )
            page.update()

    page.add(
        ft.ExpansionTile(
            expanded=True,
            title=ft.Text("ExpansionTile 1"),
            subtitle=ft.Text("Trailing expansion arrow icon"),
            affinity=ft.TileAffinity.PLATFORM,
            maintain_state=True,
            collapsed_text_color=ft.Colors.RED,
            text_color=ft.Colors.RED,
            controls=[
                ft.ListTile(title=ft.Text("This is sub-tile number 1.1")),
                ft.ListTile(title=ft.Text("This is sub-tile number 1.2")),
            ],
        ),
        ft.ExpansionTile(
            expanded=True,
            title=ft.Text("ExpansionTile 2"),
            subtitle=ft.Text("Custom expansion arrow icon"),
            trailing=ft.Icon(ft.Icons.ARROW_DROP_DOWN),
            collapsed_text_color=ft.Colors.GREEN,
            text_color=ft.Colors.GREEN,
            on_change=handle_tile_change,
            controls=[
                ft.ListTile(title=ft.Text("This is sub-tile number 2.1")),
                ft.ListTile(title=ft.Text("This is sub-tile number 2.2")),
            ],
        ),
        ft.ExpansionTile(
            expanded=True,
            title=ft.Text("ExpansionTile 3"),
            subtitle=ft.Text("Leading expansion arrow icon"),
            affinity=ft.TileAffinity.LEADING,
            collapsed_text_color=ft.Colors.BLUE_800,
            text_color=ft.Colors.BLUE_200,
            controls=[
                ft.ListTile(title=ft.Text("This is sub-tile number 3.1")),
                ft.ListTile(title=ft.Text("This is sub-tile number 3.2")),
            ],
        ),
    )


if __name__ == "__main__":
    ft.run(main)

basic.png

Programmatic expansion/collapse#

import flet as ft


def main(page: ft.Page):
    page.spacing = 20

    def expand_tile(e: ft.Event[ft.FilledButton]):
        tile.expanded = True

    def collapse_tile(e: ft.Event[ft.OutlinedButton]):
        tile.expanded = False

    page.add(
        ft.Row(
            alignment=ft.MainAxisAlignment.CENTER,
            controls=[
                ft.FilledButton("Expand Tile", on_click=expand_tile),
                ft.OutlinedButton("Collapse Tile", on_click=collapse_tile),
            ],
        ),
        tile := ft.ExpansionTile(
            title=ft.Text("I am the title of this tile.", weight=ft.FontWeight.BOLD),
            subtitle=ft.Text("This is the subtitle."),
            affinity=ft.TileAffinity.LEADING,
            controls=[ft.Text("👻", size=80)],
            expanded=True,
            on_change=lambda e: print(
                f"Tile was {'expanded' if e.data else 'collapsed'}"
            ),
        ),
    )


if __name__ == "__main__":
    ft.run(main)

Custom animations#

import flet as ft


def main(page: ft.Page):
    page.horizontal_alignment = ft.CrossAxisAlignment.CENTER
    page.spacing = 20

    def switch_animation(e: ft.Event[ft.CupertinoSlidingSegmentedButton]):
        if e.control.selected_index == 0:
            tile.animation_style = None
        elif e.control.selected_index == 1:
            tile.animation_style = ft.AnimationStyle(
                curve=ft.AnimationCurve.BOUNCE_OUT,
                duration=ft.Duration(seconds=5),
            )
        else:
            tile.animation_style = ft.AnimationStyle.no_animation()

    page.add(
        ft.CupertinoSlidingSegmentedButton(
            selected_index=0,
            thumb_color=ft.Colors.BLUE_400,
            on_change=switch_animation,
            controls=[
                ft.Text("Default animation"),
                ft.Text("Custom animation"),
                ft.Text("No animation"),
            ],
        ),
        tile := ft.ExpansionTile(
            expanded=True,
            title=ft.Text(
                "Expand/Collapse me while being attentive to the animations!"
            ),
            controls=[
                ft.ListTile(title=ft.Text("Sub-item 1")),
                ft.ListTile(title=ft.Text("Sub-item 2")),
                ft.ListTile(title=ft.Text("Sub-item 3")),
            ],
        ),
    )


if __name__ == "__main__":
    ft.run(main)

Theme mode toggle#

import flet as ft


def main(page: ft.Page):
    page.spacing = 0
    page.padding = 0

    def handle_switch_change(e: ft.Event[ft.Switch]):
        if page.theme_mode == ft.ThemeMode.DARK:
            page.theme_mode = ft.ThemeMode.LIGHT
            switch.thumb_icon = ft.Icons.LIGHT_MODE
        else:
            switch.thumb_icon = ft.Icons.DARK_MODE
            page.theme_mode = ft.ThemeMode.DARK
        page.update()

    def handle_expansion_tile_change(e: ft.Event[ft.ExpansionTile]):
        page.show_dialog(
            ft.SnackBar(
                duration=1000,
                content=ft.Text(
                    f"ExpansionTile was {'expanded' if e.data == 'true' else 'collapsed'}"
                ),
            )
        )
        if e.control.trailing:
            e.control.trailing.name = (
                ft.Icons.ARROW_DROP_DOWN
                if e.control.trailing.name == ft.Icons.ARROW_DROP_DOWN_CIRCLE
                else ft.Icons.ARROW_DROP_DOWN_CIRCLE
            )
            page.update()

    switch = ft.Switch(thumb_icon=ft.Icons.DARK_MODE, on_change=handle_switch_change)

    page.add(
        ft.ExpansionTile(
            title=ft.Text("ExpansionTile 1"),
            subtitle=ft.Text("Trailing expansion arrow icon"),
            bgcolor=ft.Colors.BLUE_GREY_200,
            collapsed_bgcolor=ft.Colors.BLUE_GREY_200,
            affinity=ft.TileAffinity.PLATFORM,
            maintain_state=True,
            collapsed_text_color=ft.Colors.RED,
            text_color=ft.Colors.RED,
            controls=[
                ft.ListTile(
                    title=ft.Text("This is sub-tile number 1"),
                    bgcolor=ft.Colors.BLUE_GREY_200,
                )
            ],
        ),
        ft.ExpansionTile(
            title=ft.Text("ExpansionTile 2"),
            subtitle=ft.Text("Custom expansion arrow icon"),
            trailing=ft.Icon(ft.Icons.ARROW_DROP_DOWN),
            collapsed_text_color=ft.Colors.GREEN,
            text_color=ft.Colors.GREEN,
            on_change=handle_expansion_tile_change,
            controls=[ft.ListTile(title=ft.Text("This is sub-tile number 2"))],
        ),
        ft.ExpansionTile(
            title=ft.Text("ExpansionTile 3"),
            subtitle=ft.Text("Leading expansion arrow icon"),
            affinity=ft.TileAffinity.LEADING,
            expanded=True,
            collapsed_text_color=ft.Colors.BLUE_800,
            text_color=ft.Colors.BLUE_200,
            controls=[
                ft.ListTile(title=ft.Text("This is sub-tile number 3")),
                ft.ListTile(title=ft.Text("This is sub-tile number 4")),
                ft.ListTile(title=ft.Text("This is sub-tile number 5")),
            ],
        ),
        ft.Row(
            expand=True,
            alignment=ft.MainAxisAlignment.END,
            controls=[
                ft.Container(
                    content=switch,
                    padding=ft.Padding.only(bottom=50),
                    alignment=ft.Alignment.BOTTOM_RIGHT,
                    expand=True,
                ),
            ],
        ),
    )


if __name__ == "__main__":
    ft.run(main)

Borders#

import flet as ft


def main(page: ft.Page):
    page.theme_mode = ft.ThemeMode.LIGHT

    page.add(
        ft.ExpansionTile(
            title=ft.Text(
                value="Expansion Tile with changing borders",
                text_align=ft.TextAlign.CENTER,
            ),
            subtitle=ft.Text(
                value="Tile border changes when expanded",
                text_align=ft.TextAlign.CENTER,
            ),
            bgcolor=ft.Colors.BLUE_GREY_200,
            controls_padding=ft.Padding.symmetric(horizontal=10),
            collapsed_bgcolor=ft.Colors.BLUE_GREY_200,
            affinity=ft.TileAffinity.PLATFORM,
            maintain_state=True,
            shape=ft.RoundedRectangleBorder(radius=20),
            collapsed_shape=ft.StadiumBorder(side=ft.BorderSide(width=2)),
            collapsed_text_color=ft.Colors.GREY_800,
            text_color=ft.Colors.GREY_800,
            controls=[
                ft.ListTile(
                    title=ft.Text("A sub-tile"),
                    bgcolor=ft.Colors.BLUE_GREY_200,
                    shape=ft.RoundedRectangleBorder(radius=20),
                    # shape=ft.StadiumBorder(),
                ),
                ft.ListTile(
                    title=ft.Text("Another sub-tile"),
                    bgcolor=ft.Colors.BLUE_GREY_200,
                    shape=ft.RoundedRectangleBorder(radius=20),
                    # shape=ft.StadiumBorder(),
                ),
            ],
        ),
    )


if __name__ == "__main__":
    ft.run(main)

Properties#

affinity class-attribute instance-attribute #

affinity: TileAffinity | None = None

Typically used to force the expansion arrow icon to the tile's leading or trailing edge.

If None, ListTileTheme.affinity is used; if that is also None, then defaults to TileAffinity.TRAILING (the expansion arrow icon appears on the tile's trailing edge).

animation_style class-attribute instance-attribute #

animation_style: AnimationStyle | None = None

Defines the animation style (curve and duration) for this tile's expansion and collapse.

If AnimationStyle.duration is provided, it will be used to override the expansion animation duration. If it is None, then AnimationStyle.duration from the [ExpansionTileTheme.animation_style][flet.controls.material.expansion_tile.ExpansionTile.ExpansionTileTheme.animation_style] will be used. If that is also None, Duration(milliseconds=200) will be used as default.

If AnimationStyle.curve is provided, it will be used to override the expansion animation curve. If it is None, then AnimationStyle.curve from the [ExpansionTileTheme.animation_style][flet.controls.material.expansion_tile.ExpansionTile.ExpansionTileTheme.animation_style] will be used. If that is also None, [Curves.EASE_IN][flet.Curves.EASE_IN] will be used as default.

If AnimationStyle.reverse_curve is provided, it will be used to override the collapse animation curve. If it is None, then AnimationStyle.reverse_curve from the [ExpansionTileTheme.animation_style][flet.controls.material.expansion_tile.ExpansionTile.ExpansionTileTheme.animation_style] will be used. If that is also None, the expansion curve will be used as default.

Tip

To disable the animations, use AnimationStyle.no_animation().

bgcolor class-attribute instance-attribute #

bgcolor: ColorValue | None = None

The color to display behind the sublist when expanded.

If None, ExpansionTileTheme.bgcolor is used; if that is also None, then defaults to Colors.TRANSPARENT.

clip_behavior class-attribute instance-attribute #

clip_behavior: ClipBehavior | None = None

Defines how the content of this tile is clipped.

If set and a custom collapsed or expanded shape is provided, this value determines how this tile is clipped.

If None, ExpansionTileTheme.clip_behavior is used; if that is also None, then defaults to ClipBehavior.ANTI_ALIAS.

collapsed_bgcolor class-attribute instance-attribute #

collapsed_bgcolor: ColorValue | None = None

Defines the background color of this tile when the sublist is collapsed (expanded is False).

If None, ExpansionTileTheme.collapsed_bgcolor is used; if that is also None, then defaults to Colors.TRANSPARENT.

collapsed_icon_color class-attribute instance-attribute #

collapsed_icon_color: ColorValue | None = None

The icon color of this tile's expansion arrow icon when the sublist is collapsed (expanded is False).

If None, ExpansionTileTheme.collapsed_icon_color is used; if that is also None, then defaults to ColorScheme.on_surface of the Page.theme.

collapsed_shape class-attribute instance-attribute #

collapsed_shape: OutlinedBorder | None = None

The tile's border shape when the sublist is collapsed.

If None, ExpansionTileTheme.shape is used; if that is also None, then defaults to a Border with vertical sides of color Colors.TRANSPARENT.

collapsed_text_color class-attribute instance-attribute #

collapsed_text_color: ColorValue | None = None

The color of this tile's titles when the sublist is collapsed (expanded is False).

If None, ExpansionTileTheme.collapsed_text_color is used; if that is also None, then defaults to body_large of the Theme.text_theme.

controls class-attribute instance-attribute #

controls: list[Control] | None = None

The controls to be displayed when this tile expands.

Typically a list of ListTile controls.

controls_padding class-attribute instance-attribute #

controls_padding: PaddingValue | None = None

Defines the padding around the controls.

If None, ExpansionTileTheme.controls_padding is used; if that is also None, then defaults to Padding.all(0).

dense class-attribute instance-attribute #

dense: bool | None = None

Whether this list tile is part of a vertically dense list.

Dense tiles default to having a smaller height.

It is not recommended to set this property to True when in Material3.

If None, then its value is based on ListTileTheme.dense.

enable_feedback class-attribute instance-attribute #

enable_feedback: bool = True

Whether detected gestures should provide acoustic and/or haptic feedback. For example, on Android a tap will produce a clicking sound and a long-press will produce a short vibration, when feedback is enabled.

expanded class-attribute instance-attribute #

expanded: bool = False

The expansion state of this tile.

True - expanded, False - collapsed.

expanded_alignment class-attribute instance-attribute #

expanded_alignment: Alignment | None = None

Defines the alignment of controls, which are arranged in a column when the tile is expanded.

If None, ExpansionTileTheme.expanded_alignment is used; if that is also None, then defaults to Alignment.CENTER.

expanded_cross_axis_alignment class-attribute instance-attribute #

expanded_cross_axis_alignment: CrossAxisAlignment = CENTER

Defines the alignment of each child control within controls when the tile is expanded.

Raises:

icon_color class-attribute instance-attribute #

icon_color: ColorValue | None = None

The icon color of this tile's expansion arrow icon when the sublist is expanded.

If None, ExpansionTileTheme.icon_color is used; if that is also None, then defaults to ColorScheme.primary of the Page.theme.

leading class-attribute instance-attribute #

leading: IconDataOrControl | None = None

A Control to display before the title.

Typically a CircleAvatar control.

Depending on the value of affinity, this control may replace the rotating expansion arrow icon.

maintain_state class-attribute instance-attribute #

maintain_state: bool = False

A boolean value which defines whether the state of the controls is maintained when this tile expands and collapses.

When True, the children are kept in the tree while the tile is collapsed. When False (default), the controls are removed from the tree when the tile is collapsed and recreated upon expansion.

min_tile_height class-attribute instance-attribute #

min_tile_height: Number | None = None

The minimum height of this tile.

If None, the default tile heights are 56.0, 72.0, and 88.0 for one, two, and three lines of text respectively. If dense is True, these defaults are changed to 48.0, 64.0, and 76.0. A visual density value or a large title will also adjust the default tile heights.

shape class-attribute instance-attribute #

shape: OutlinedBorder | None = None

The border shape of this tile when the sublist is expanded.

If None, ExpansionTileTheme.shape is used; if that is also None, then defaults to a Border with vertical sides of color [Theme.divider_color][flet.Theme.divider_color].

show_trailing_icon class-attribute instance-attribute #

show_trailing_icon: bool = True

Whether this tile should build/show a default trailing icon, if trailing is None.

subtitle class-attribute instance-attribute #

subtitle: StrOrControl | None = None

Additional content displayed below the title.

Typically a Text control.

text_color class-attribute instance-attribute #

text_color: ColorValue | None = None

The color of this tile's titles when the sublist is expanded.

If None, ExpansionTileTheme.text_color is used; if that is also None, then defaults to body_large of the Theme.text_theme.

tile_padding class-attribute instance-attribute #

tile_padding: PaddingValue | None = None

Defines the tile's padding.

Analogous to ListTile.content_padding, this property defines the insets for the leading, title, subtitle and trailing controls. It does not inset the expanded controls widgets.

If None, ExpansionTileTheme.tile_padding is used; if that is also None, then defaults to Padding.symmetric(horizontal=16.0).

title instance-attribute #

title: StrOrControl

A Control to display as primary content of this tile.

Typically a Text control.

Raises:

  • ValueError

    If it is neither a string nor a visible Control.

trailing class-attribute instance-attribute #

trailing: IconDataOrControl | None = None

A Control to display after the title.

Typically an Icon control.

Depending on the value of affinity, this control may replace the rotating expansion arrow icon.

visual_density class-attribute instance-attribute #

visual_density: VisualDensity | None = None

Defines how compact this tile's layout will be.

Events#

on_change class-attribute instance-attribute #

on_change: ControlEventHandler[ExpansionTile] | None = None

Called when a user clicks or taps the list tile.

The data property of the event handler argument is a boolean representing the expanded state of the tile after the change.