# Flex Layout > Advanced docking layout system with resizable panels, floating windows, and theme integration. --- .. toc:: .. llms_copy::Flex Layout `flexlayout-dash` is a Dash component library that provides a flexible, dock-able layout system for building professional dashboard interfaces. It features resizable and draggable panels, floating windows with pop-out support, multiple layout types (horizontal, vertical, nested), collapsible sidebar borders, theme integration with Mantine, state persistence, and extensive customization options for creating IDE-style layouts, dashboards, and complex multi-panel applications. ### Installation [Visit GitHub Repo](https://github.com/pip-install-python/flexlayout-dash) ⭐️ Star this component on GitHub! Stay up to date on new releases and browse the codebase. ```bash pip install flexlayout-dash ``` **Requirements:** - Python >= 3.7 - Dash >= 2.0 - dash-mantine-components (recommended for theming) --- ### Quick Start Create a simple two-panel layout with resizable divider. .. exec::docs.dash_flex_layout.introduction :code: false ```python # File: docs/dash_flex_layout/introduction.py """ Dash Flex Layout - Quick Start Example ====================================== A simple two-panel layout with resizable divider. """ import dash_mantine_components as dmc import dash_flex_layout as dfl # Define the layout model with 50/50 horizontal split model = { "global": { "tabEnableClose": False, # Prevent closing tabs "tabEnableRenderOnDemand": False, # Keep all tabs mounted for callbacks }, "layout": { "type": "row", # Horizontal split "children": [ { "type": "tabset", "weight": 50, # 50% of width "children": [ { "type": "tab", "name": "Left Panel", "id": "left-panel", } ] }, { "type": "tabset", "weight": 50, # 50% of width "children": [ { "type": "tab", "name": "Right Panel", "id": "right-panel", } ] } ] } } # Create tab components with content tabs = [ dfl.Tab( id="left-panel", children=[ dmc.Stack([ dmc.Title("Welcome to Flex Layout", order=3), dmc.Text( "This is a simple two-panel layout with a resizable divider. " "Drag the divider in the middle to adjust panel sizes.", size="sm" ), dmc.Badge("Left Panel", color="blue", size="lg", mt="md"), ], p="md") ] ), dfl.Tab( id="right-panel", children=[ dmc.Stack([ dmc.Title("Right Panel", order=3), dmc.Text( "Panels automatically adjust their size based on the weight property. " "Both panels have equal weight (50), so they split evenly.", size="sm" ), dmc.Badge("Right Panel", color="green", size="lg", mt="md"), ], p="md") ] ), ] # Main component for rendering component = dmc.Stack([ dmc.Alert( children="Try resizing the panels by dragging the divider!", title="Quick Start", color="blue", ), dmc.Box( style={"height": "400px", "width": "100%", "position": "relative"}, children=dfl.DashFlexLayout( id='flex-layout-intro', model=model, children=tabs, style={"height": "100%", "width": "100%"}, useStateForModel=True, supportsPopout=False, ) ) ], gap="md") ``` --- ### Two-Panel Layouts Split your interface horizontally or vertically using the weight system. The weight determines how much space each panel occupies relative to others. ```python import dash_flex_layout as dfl # 50/50 split model = { "global": {"tabEnableClose": False, "tabEnableRenderOnDemand": False}, "layout": { "type": "row", # Horizontal split "children": [ {"type": "tabset", "weight": 50, "children": [{"type": "tab", "name": "Left", "id": "left"}]}, {"type": "tabset", "weight": 50, "children": [{"type": "tab", "name": "Right", "id": "right"}]} ] } } # Create tabs tabs = [ dfl.Tab(id="left", children=[...]), dfl.Tab(id="right", children=[...]) ] # Render layout dfl.DashFlexLayout( id='layout', model=model, children=tabs, useStateForModel=True, supportsPopout=False, ) ``` **Weight System:** - Weights are relative values (e.g., 70/30 creates a 70%-30% split) - Total weights don't need to sum to 100 - Adjust weights to create custom proportions (e.g., 2:1 ratio = weights 66:33) --- ### Multiple Tabs Organize multiple views within a single panel using tabs. Users can click tabs to switch between different content. .. exec::docs.dash_flex_layout.two_panel_layout :code: false ```python # File: docs/dash_flex_layout/two_panel_layout.py """ Dash Flex Layout - Multiple Tabs Example ========================================= Single tabset with multiple tabs for navigation. """ import dash_mantine_components as dmc import dash_flex_layout as dfl from dash_iconify import DashIconify # Define the layout model with single tabset model = { "global": { "tabEnableClose": False, "tabEnableFloat": True, # Allow floating tabs "tabEnableRenderOnDemand": False, # Keep all tabs mounted }, "layout": { "type": "row", "children": [ { "type": "tabset", "weight": 100, # Full width "selected": 0, # Initially selected tab (Overview) "children": [ {"type": "tab", "name": "Overview", "id": "tab-overview"}, {"type": "tab", "name": "Details", "id": "tab-details"}, {"type": "tab", "name": "Settings", "id": "tab-settings"} ] } ] } } # Create tab components tabs = [ dfl.Tab( id="tab-overview", children=[ dmc.Card([ dmc.Group([ DashIconify(icon="mdi:view-dashboard", width=32, color="blue"), dmc.Title("Overview", order=3) ], gap="sm"), dmc.Text( "This tab shows an overview of your data. Multiple tabs allow you to organize " "different views within the same panel.", size="sm", mt="md" ), dmc.SimpleGrid([ dmc.Paper([ dmc.Text("Total Users", size="xs", c="dimmed"), dmc.Title("1,234", order=2), ], p="md", withBorder=True), dmc.Paper([ dmc.Text("Active Now", size="xs", c="dimmed"), dmc.Title("567", order=2), ], p="md", withBorder=True), dmc.Paper([ dmc.Text("Revenue", size="xs", c="dimmed"), dmc.Title("$12.3k", order=2), ], p="md", withBorder=True), ], cols=3, mt="xl") ], p="xl") ] ), dfl.Tab( id="tab-details", children=[ dmc.Card([ dmc.Group([ DashIconify(icon="mdi:information-outline", width=32, color="green"), dmc.Title("Details", order=3) ], gap="sm"), dmc.Text( "Detailed information and analytics are shown in this tab. " "Switch between tabs to see different content.", size="sm", mt="md" ), dmc.Stack([ dmc.Text("• Flexible tab navigation", size="sm"), dmc.Text("• Organize content into logical groups", size="sm"), dmc.Text("• Easy to understand structure", size="sm"), dmc.Text("• Customizable tab names and icons", size="sm"), ], gap="xs", mt="xl") ], p="xl") ] ), dfl.Tab( id="tab-settings", children=[ dmc.Card([ dmc.Group([ DashIconify(icon="mdi:cog-outline", width=32, color="orange"), dmc.Title("Settings", order=3) ], gap="sm"), dmc.Text( "Configuration and preferences go here. Each tab can contain " "any Dash components you need.", size="sm", mt="md" ), dmc.Stack([ dmc.Switch(label="Enable notifications", checked=True, mt="lg"), dmc.Switch(label="Auto-save changes", checked=False), dmc.Switch(label="Dark mode", checked=False), ], gap="md", mt="xl") ], p="xl") ] ), ] # Main component for rendering component = dmc.Stack([ dmc.Alert( children="Click on different tabs to navigate between views!", title="Multiple Tabs", color="teal", ), dmc.Box( style={"height": "450px", "width": "100%", "position": "relative"}, children=dfl.DashFlexLayout( id='flex-layout-tabs', model=model, children=tabs, style={"height": "100%", "width": "100%"}, useStateForModel=True, supportsPopout=False, ) ) ], gap="md") ``` **Tab Configuration:** - Set `selected: 0` in tabset to choose initially selected tab (zero-indexed) - Enable `tabEnableFloat: True` to allow tabs to be popped out into floating windows - Each tab needs a unique `id` that matches a Tab component --- ### Vertical Layouts Use `"type": "column"` to create vertical splits with top/bottom panels. ```python model = { "global": {"tabEnableClose": False, "tabEnableRenderOnDemand": False}, "layout": { "type": "column", # Vertical split "children": [ {"type": "tabset", "weight": 40, "children": [{"type": "tab", "name": "Top", "id": "top"}]}, {"type": "tabset", "weight": 60, "children": [{"type": "tab", "name": "Bottom", "id": "bottom"}]} ] } } ``` **Use Cases:** - Dashboard with chart on top and data table below - Editor with preview panel underneath - Main content with footer panel --- ### Nested Layouts Combine rows and columns to create complex multi-panel interfaces. Perfect for IDE-style layouts and advanced dashboards. .. exec::docs.dash_flex_layout.ide_layout :code: false ```python # File: docs/dash_flex_layout/ide_layout.py """ Dash Flex Layout - Nested Layout Example ========================================== Simple nested layout demonstrating rows within columns. """ import dash_mantine_components as dmc import dash_flex_layout as dfl # Define nested layout model (no borders for simplicity) model = { "global": { "tabEnableClose": False, "tabEnableRenderOnDemand": False, }, "layout": { "type": "row", "children": [ { "type": "column", "weight": 70, "children": [ { "type": "tabset", "weight": 60, "children": [ {"type": "tab", "name": "Editor", "id": "editor"} ] }, { "type": "tabset", "weight": 40, "children": [ {"type": "tab", "name": "Terminal", "id": "terminal"} ] } ] }, { "type": "tabset", "weight": 30, "children": [ {"type": "tab", "name": "Preview", "id": "preview"} ] } ] } } # Create tab components tabs = [ # Editor Tab (top left) dfl.Tab( id="editor", children=[ dmc.Box( p="md", children=[ dmc.Title("Code Editor", order=4, mb="md"), dmc.Code( block=True, children="""from dash import Dash import dash_mantine_components as dmc app = Dash(__name__) app.layout = dmc.Container([ dmc.Title("Hello Dash"), dmc.Text("Nested layouts!") ]) if __name__ == '__main__': app.run(debug=True)""", style={ "fontSize": "13px", } ) ] ) ] ), # Terminal Tab (bottom left) dfl.Tab( id="terminal", children=[ dmc.Box( p="md", children=[ dmc.Title("Terminal", order=4, mb="md"), dmc.Code( block=True, children="""$ python app.py Dash is running on http://127.0.0.1:8050/ * Debug mode: on""", style={ "fontSize": "13px", "backgroundColor": "var(--mantine-color-dark-6)", "color": "var(--mantine-color-green-4)", } ) ] ) ] ), # Preview Tab (right side) dfl.Tab( id="preview", children=[ dmc.Box( p="md", children=[ dmc.Title("Live Preview", order=4, mb="md"), dmc.Paper( p="xl", withBorder=True, children=[ dmc.Title("Hello Dash", order=2, mb="xs"), dmc.Text("Nested layouts!", c="dimmed") ] ) ] ) ] ), ] # Main component for rendering component = dmc.Stack( gap="md", children=[ dmc.Alert( color="violet", variant="light", children=[ dmc.Text("Nested Layouts", fw=700, mb="xs"), dmc.Text("Nested layout with a vertical split on the left (Editor/Terminal) and Preview panel on the right.") ] ), dmc.Box( style={"height": "500px", "width": "100%", "position": "relative"}, children=dfl.DashFlexLayout( id='flex-layout-nested', model=model, children=tabs, style={"height": "100%", "width": "100%"}, useStateForModel=True, supportsPopout=False, ) ) ] ) ``` **Nested Example:** ```python "layout": { "type": "row", "children": [ { "type": "column", # Nested vertical split "weight": 70, "children": [ {"type": "tabset", "weight": 60, "children": [...]}, {"type": "tabset", "weight": 40, "children": [...]} ] }, {"type": "tabset", "weight": 30, "children": [...]} # Right sidebar ] } ``` --- ### Borders (Sidebars) Create collapsible sidebars on the left, right, or bottom edges using borders. Perfect for navigation, tools, or secondary content. ```python model = { "global": {...}, "borders": [ { "type": "border", "location": "left", # "left", "right", or "bottom" "size": 250, # Width in pixels "selected": 0, # Initially selected tab "children": [ {"type": "tab", "name": "Files", "id": "files"}, {"type": "tab", "name": "Search", "id": "search"} ] } ], "layout": { "type": "row", "children": [...] # Main content area } } ``` **Border Features:** - Click border button to expand/collapse - Support left, right, and bottom positions (**Note**: top borders not supported) - Can contain multiple tabs like regular tabsets - Size in pixels (width for left/right, height for bottom) --- ### Theme Integration Flex Layout automatically detects your app's color scheme from MantineProvider and adjusts colors accordingly. .. exec::docs.dash_flex_layout.theming_example :code: false ```python # File: docs/dash_flex_layout/theming_example.py """ Liquid Glass Themes Example for Dash Flex Layout ================================================= Showcases Apple WWDC 2025 inspired liquid glass design with light/dark themes. This example is completely isolated and won't affect other DashFlexLayout instances. """ from dash import callback, Input, Output import dash_mantine_components as dmc from dash_iconify import DashIconify import dash_flex_layout as dfl # Inline style definitions for glass effects GLASS_CONTAINER_STYLE_DARK = { "background": "linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%)", "borderRadius": "16px", "padding": "4px", "position": "relative", "transition": "background 0.3s ease", } GLASS_CONTAINER_STYLE_LIGHT = { "background": "linear-gradient(135deg, #e8f4f8 0%, #d4e5f7 50%, #c1d5eb 100%)", "borderRadius": "16px", "padding": "4px", "position": "relative", "transition": "background 0.3s ease", } GLASS_PANEL_STYLE_DARK = { "backdropFilter": "blur(20px) saturate(180%)", "WebkitBackdropFilter": "blur(20px) saturate(180%)", "background": "linear-gradient(135deg, rgba(255, 255, 255, 0.08) 0%, rgba(255, 255, 255, 0.05) 100%)", "border": "1px solid rgba(255, 255, 255, 0.15)", "boxShadow": "0 8px 32px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.1)", "borderRadius": "12px", "padding": "1rem", "height": "100%", "overflow": "auto", } GLASS_PANEL_STYLE_LIGHT = { "backdropFilter": "blur(20px) saturate(180%)", "WebkitBackdropFilter": "blur(20px) saturate(180%)", "background": "linear-gradient(135deg, rgba(255, 255, 255, 0.7) 0%, rgba(255, 255, 255, 0.5) 100%)", "border": "1px solid rgba(255, 255, 255, 0.5)", "boxShadow": "0 8px 32px rgba(31, 38, 135, 0.25), inset 0 1px 0 rgba(255, 255, 255, 0.8)", "borderRadius": "12px", "padding": "1rem", "height": "100%", "overflow": "auto", } FEATURE_CARD_STYLE_DARK = { "backdropFilter": "blur(16px) saturate(160%)", "WebkitBackdropFilter": "blur(16px) saturate(160%)", "background": "rgba(45, 55, 72, 0.6)", "border": "1px solid rgba(255, 255, 255, 0.1)", "borderRadius": "10px", "padding": "1rem", "marginBottom": "0.5rem", } FEATURE_CARD_STYLE_LIGHT = { "backdropFilter": "blur(16px) saturate(160%)", "WebkitBackdropFilter": "blur(16px) saturate(160%)", "background": "rgba(255, 255, 255, 0.7)", "border": "1px solid rgba(0, 0, 0, 0.05)", "borderRadius": "10px", "padding": "1rem", "marginBottom": "0.5rem", } # Define layout model model = { "global": { "tabEnableClose": False, "tabEnableRenderOnDemand": False, }, "layout": { "type": "row", "children": [ { "type": "tabset", "weight": 30, "children": [ {"type": "tab", "name": "Overview", "id": "theme-overview"} ] }, { "type": "tabset", "weight": 40, "children": [ {"type": "tab", "name": "Features", "id": "theme-features"} ] }, { "type": "tabset", "weight": 30, "children": [ {"type": "tab", "name": "Metrics", "id": "theme-metrics"} ] } ] } } def create_overview_panel(theme="dark"): """Create overview panel with theme switcher.""" glass_style = GLASS_PANEL_STYLE_DARK if theme == "dark" else GLASS_PANEL_STYLE_LIGHT return dmc.Box( id="theme-overview", style=glass_style, children=[ dmc.Stack( gap="md", children=[ dmc.Group( justify="space-between", children=[ dmc.Group( gap="sm", children=[ DashIconify(icon="mdi:palette-advanced", width=32, color="#4FC3F7"), dmc.Stack( gap=0, children=[ dmc.Title("Liquid Glass", order=4), dmc.Text("Apple WWDC 2025", size="xs", c="dimmed"), ] ), ] ), dmc.SegmentedControl( id="flex-theme-switcher", data=[ {"value": "dark", "label": "🌙 Dark"}, {"value": "light", "label": "☀️ Light"}, ], value=theme, color="blue", radius="lg", size="sm", ), ] ), dmc.Divider(opacity=0.2), dmc.Text( "Experience Apple's next-generation glassmorphism design with backdrop blur, translucency, and gradient overlays.", size="sm", c="dimmed", ), dmc.Group( gap="xs", mt="sm", children=[ dmc.Badge("20px Blur", variant="dot", color="cyan", size="sm"), dmc.Badge("180% Saturation", variant="dot", color="violet", size="sm"), dmc.Badge("Glass Morphism", variant="dot", color="orange", size="sm"), ] ), ] ) ] ) def create_features_panel(theme="dark"): """Create features showcase panel.""" card_style = FEATURE_CARD_STYLE_DARK if theme == "dark" else FEATURE_CARD_STYLE_LIGHT return dmc.Box( id="theme-features", style=GLASS_PANEL_STYLE_DARK if theme == "dark" else GLASS_PANEL_STYLE_LIGHT, children=[ dmc.Stack( gap="sm", children=[ dmc.Title("Key Features", order=5, mb="xs"), dmc.Box( style=card_style, children=[ dmc.Group( gap="sm", mb="xs", children=[ DashIconify(icon="mdi:blur", width=18, color="#4FC3F7"), dmc.Text("Backdrop Blur", fw=600, size="sm"), ] ), dmc.Text( "Advanced blur effects with 20px radius and 180% saturation.", size="xs", c="dimmed", ), ] ), dmc.Box( style=card_style, children=[ dmc.Group( gap="sm", mb="xs", children=[ DashIconify(icon="mdi:opacity", width=18, color="#9C27B0"), dmc.Text("Translucency", fw=600, size="sm"), ] ), dmc.Text( "Semi-transparent gradients that adapt to light and dark modes.", size="xs", c="dimmed", ), ] ), dmc.Box( style=card_style, children=[ dmc.Group( gap="sm", mb="xs", children=[ DashIconify(icon="mdi:gradient-vertical", width=18, color="#FFC107"), dmc.Text("Liquid Borders", fw=600, size="sm"), ] ), dmc.Text( "Smooth gradient borders with animated effects.", size="xs", c="dimmed", ), ] ), dmc.Box( style=card_style, children=[ dmc.Group( gap="sm", mb="xs", children=[ DashIconify(icon="mdi:theme-light-dark", width=18, color="#00BCD4"), dmc.Text("Theme Aware", fw=600, size="sm"), ] ), dmc.Text( "Automatically adapts to light and dark color schemes.", size="xs", c="dimmed", ), ] ), ] ) ] ) def create_metrics_panel(theme="dark"): """Create metrics panel.""" card_style = FEATURE_CARD_STYLE_DARK if theme == "dark" else FEATURE_CARD_STYLE_LIGHT return dmc.Box( id="theme-metrics", style=GLASS_PANEL_STYLE_DARK if theme == "dark" else GLASS_PANEL_STYLE_LIGHT, children=[ dmc.Stack( gap="md", children=[ dmc.Title("Design Metrics", order=5), dmc.Box( style=card_style, children=[ dmc.Group( justify="space-between", align="center", children=[ dmc.Stack( gap=0, children=[ dmc.Text("Blur Radius", size="xs", c="dimmed"), dmc.Title("20px", order=4, c="cyan"), ] ), DashIconify(icon="mdi:blur-radial", width=28, color="#4FC3F7", style={"opacity": 0.6}), ] ), ] ), dmc.Box( style=card_style, children=[ dmc.Group( justify="space-between", align="center", children=[ dmc.Stack( gap=0, children=[ dmc.Text("Saturation", size="xs", c="dimmed"), dmc.Title("180%", order=4, c="violet"), ] ), DashIconify(icon="mdi:palette", width=28, color="#9C27B0", style={"opacity": 0.6}), ] ), ] ), dmc.Box( style=card_style, children=[ dmc.Group( justify="space-between", align="center", children=[ dmc.Stack( gap=0, children=[ dmc.Text("Opacity", size="xs", c="dimmed"), dmc.Title("65%", order=4, c="orange"), ] ), DashIconify(icon="mdi:opacity", width=28, color="#FFC107", style={"opacity": 0.6}), ] ), ] ), ] ) ] ) # Create tabs with default dark theme tabs_dark = [ dfl.Tab(id="theme-overview", children=[create_overview_panel("dark")]), dfl.Tab(id="theme-features", children=[create_features_panel("dark")]), dfl.Tab(id="theme-metrics", children=[create_metrics_panel("dark")]), ] # Main component component = dmc.Stack( gap="md", children=[ dmc.Alert( color="indigo", variant="light", children=[ dmc.Text("Liquid Glass Theme Demo", fw=700, mb="xs"), dmc.Text("Toggle between light and dark themes to see the glassmorphism effect adapt dynamically!") ] ), dmc.Box( id="flex-glass-container", style=GLASS_CONTAINER_STYLE_DARK, children=[ dmc.Box( style={"height": "450px", "position": "relative"}, children=dfl.DashFlexLayout( id='flex-layout-glass-theme', model=model, children=tabs_dark, style={"height": "100%", "width": "100%"}, useStateForModel=True, supportsPopout=False, ) ) ] ) ] ) # Callback to switch themes @callback( Output("flex-glass-container", "style"), Output("flex-layout-glass-theme", "children"), Input("flex-theme-switcher", "value"), ) def switch_flex_glass_theme(theme_value): """Toggle between liquid glass light and dark themes.""" if theme_value == "light": tabs = [ dfl.Tab(id="theme-overview", children=[create_overview_panel("light")]), dfl.Tab(id="theme-features", children=[create_features_panel("light")]), dfl.Tab(id="theme-metrics", children=[create_metrics_panel("light")]), ] return GLASS_CONTAINER_STYLE_LIGHT, tabs else: tabs = [ dfl.Tab(id="theme-overview", children=[create_overview_panel("dark")]), dfl.Tab(id="theme-features", children=[create_features_panel("dark")]), dfl.Tab(id="theme-metrics", children=[create_metrics_panel("dark")]), ] return GLASS_CONTAINER_STYLE_DARK, tabs ``` **Theme Options:** - **Automatic Detection**: Component reads theme from MantineProvider context - **Manual Override**: Use `colorScheme="light"` or `colorScheme="dark"` prop - **Liquid Glass Themes**: Available via custom CSS (see assets/flexlayout-dock.css) **Custom CSS:** ```css /* Apply custom styles to flexlayout */ :root[data-mantine-color-scheme="light"] .flexlayout__layout { background: rgba(255, 255, 255, 0.95); backdrop-filter: blur(10px); } :root[data-mantine-color-scheme="dark"] .flexlayout__layout { background: rgba(30, 30, 35, 0.95); backdrop-filter: blur(10px); } ``` --- ### Interactive Callbacks Use callbacks to create dynamic, interactive layouts with real-time updates. .. exec::docs.dash_flex_layout.callbacks_example :code: false ```python # File: docs/dash_flex_layout/callbacks_example.py """ Dash Flex Layout - Interactive Callbacks Example ================================================= Demonstrates callbacks and dynamic content updates. """ from dash import callback, Input, Output, dcc import dash_mantine_components as dmc import dash_flex_layout as dfl import json # Define 3-panel layout model model = { "global": { "tabEnableClose": False, "tabEnableRenderOnDemand": False, # CRITICAL for callbacks! }, "layout": { "type": "row", "children": [ { "type": "tabset", "weight": 30, "children": [ {"type": "tab", "name": "Controls", "id": "controls-panel"} ] }, { "type": "tabset", "weight": 40, "children": [ {"type": "tab", "name": "Output", "id": "output-panel"} ] }, { "type": "tabset", "weight": 30, "children": [ {"type": "tab", "name": "Data", "id": "data-panel"} ] } ] } } # Create tab components tabs = [ dfl.Tab( id="controls-panel", children=[ dmc.Stack( p="md", gap="md", children=[ dmc.Title("Controls", order=4), dmc.Select( id="value-select", label="Select a value:", data=[ {"label": "Option 1", "value": "opt1"}, {"label": "Option 2", "value": "opt2"}, {"label": "Option 3", "value": "opt3"}, ], value="opt1" ), dmc.NumberInput( id="number-input", label="Enter a number:", value=5, min=1, max=10, ), dmc.Button( "Update Output", id="update-button", fullWidth=True, color="blue" ), ] ) ] ), dfl.Tab( id="output-panel", children=[ dmc.Stack( p="md", gap="md", children=[ dmc.Title("Output", order=4), dmc.Paper( id="output-container", p="md", withBorder=True, style={"minHeight": "200px"}, children=[ dmc.Center( p="xl", children=dmc.Text("Click 'Update Output' to see results here", c="dimmed") ) ] ), ] ) ] ), dfl.Tab( id="data-panel", children=[ dmc.Stack( p="md", gap="md", children=[ dmc.Title("Data Preview", order=4), dmc.Code( id="data-display", block=True, children="Click 'Update Output' to see data here", style={ "fontSize": "12px", "minHeight": "200px" } ), ] ) ] ), ] # Callback to generate data and update output @callback( Output("output-container", "children"), Output("data-display", "children"), Input("update-button", "n_clicks"), Input("number-input", "value"), Input("value-select", "value"), ) def update_output(n_clicks, number, selected_value): # Generate output data data = { "selected": selected_value, "number": number, "result": number * 10 } # Create output display output = dmc.Stack( p="md", gap="sm", children=[ dmc.Title(f"Result: {data['result']}", order=3, c="blue"), dmc.Text(f"You selected: {selected_value}"), dmc.Text(f"Number entered: {number}"), dmc.Text(f"Calculation: {number} × 10 = {data['result']}"), ] ) # Format data display data_json = json.dumps(data, indent=2) return output, data_json # Main component for rendering component = dmc.Stack( gap="md", children=[ dmc.Alert( color="grape", variant="light", children=[ dmc.Text("Interactive Callbacks", fw=700, mb="xs"), dmc.Text("Use the controls to update the output and data preview. Callbacks work seamlessly with FlexLayout!") ] ), dmc.Box( style={"height": "500px", "position": "relative"}, children=dfl.DashFlexLayout( id='flex-layout-callbacks', model=model, children=tabs, style={"height": "100%", "width": "100%"}, useStateForModel=True, supportsPopout=False, ) ) ] ) ``` **CRITICAL: Set `tabEnableRenderOnDemand: False`** ```python model = { "global": { "tabEnableRenderOnDemand": False, # Required for callbacks! }, ... } ``` Without this setting, tabs are unmounted when not visible, causing callbacks to fail. **Callback Best Practices:** - Use `useStateForModel=True` to avoid excessive callback triggers - Define all chart/component types upfront, toggle visibility with styles - Don't dynamically replace `children` in callbacks—update props instead - Read layout state via `Input('layout-id', 'model')` if needed --- ### Model Configuration The `model` prop defines the entire layout structure using a JSON-like dictionary. **Global Settings:** ```python "global": { "tabEnableClose": False, # Allow closing tabs "tabEnableFloat": True, # Allow floating tabs as windows "tabEnableRenderOnDemand": False, # CRITICAL: Keep all tabs mounted for callbacks "tabEnableMaximize": True, # Allow maximizing tabsets "tabEnableDrag": True, # Allow dragging tabs } ``` **Layout Structure:** ```python "layout": { "type": "row", # "row" (horizontal) or "column" (vertical) "weight": 100, # Relative size percentage "children": [...] # Array of tabsets or nested layouts } ``` **Tabset:** ```python { "type": "tabset", "weight": 50, # 50% of parent width/height "selected": 0, # Initially selected tab index "children": [...] # Array of tab objects } ``` **Tab:** ```python { "type": "tab", "name": "Tab Name", # Display name "id": "unique-id", # Must match Tab component id "enableClose": True, # Override global setting } ``` --- ### Component Properties #### DashFlexLayout Properties | Property | Type | Default | Description | | :---------- | :---------- | :---------- | :---------- | | **`id`** | `string` | **Required** | Unique identifier for the component used in Dash callbacks. | | **`model`** | `dict` | **Required** | Layout configuration object defining structure, global settings, and borders. | | **`children`** | `list[Tab]` | **Required** | List of Tab components. Each Tab id must match a tab id in the model. | | `headers` | `dict` | `None` | Custom header components for tabs. Keys are tab IDs, values are Dash components. | | `useStateForModel` | `bool` | `False` | Use internal state management for model. Recommended: `True` to avoid excessive callbacks. | | `colorScheme` | `string` | Auto-detect | Force color scheme: `"light"` or `"dark"`. Auto-detects from MantineProvider if not set. | | `supportsPopout` | `bool` | `True` | Enable pop-out windows for floating tabs. Set to `False` to disable. | | `popoutURL` | `string` | `"/assets/popout.html"` | URL for pop-out window HTML template. | | `realtimeResize` | `bool` | `False` | Resize panels in real-time during drag (performance impact). | | `debugMode` | `bool` | `False` | Enable debug logging to console. | | `style` | `dict` | `None` | CSS styles for the container element. | | `font` | `string` | `None` | Custom font family for layout UI. | | `loading_state` | `object` | (Dash Internal) | Object describing the loading state of the component. | #### Tab Properties | Property | Type | Default | Description | | :---------- | :---------- | :---------- | :---------- | | **`id`** | `string` | **Required** | Unique identifier that must match a tab id in the model configuration. | | **`children`** | `list` | **Required** | Dash components to render inside the tab panel. | --- ### Best Practices **For Callbacks:** - Always set `tabEnableRenderOnDemand: False` in global config - Use `useStateForModel=True` to avoid excessive callback triggers - Define all chart types upfront, toggle visibility with styles - Don't dynamically replace children in callbacks **For Layout Design:** - Use weight system for responsive sizing (e.g., 70/30 splits) - Keep nested layouts shallow (max 2-3 levels deep) - Test mobile responsiveness with smaller weights - Use borders for collapsible sidebars **For Theming:** - Let component auto-detect Mantine theme when possible - Use `colorScheme` prop only to force specific theme - Apply custom CSS to `.flexlayout__layout` class - Test both light and dark modes --- ### Troubleshooting **Callbacks Not Firing:** - Ensure `tabEnableRenderOnDemand: False` in global config - Verify tab IDs match between model and Tab components **Layout Not Filling Container:** - Set explicit height on parent container - Example: `style={"height": "100vh"}` or `h="500px"` **Tabs Not Appearing:** - Check that Tab component `id` matches tab `id` in model - Verify children list includes all Tab components **Theme Not Applying:** - Ensure MantineProvider wraps the layout - Check that colorScheme prop matches theme **Pop-out Windows Not Working:** - Verify `supportsPopout=True` (default) - Check that popoutURL points to valid HTML file - Ensure HTML file has proper window communication setup --- ### Contributing Contributions to flexlayout-dash are welcome! Please refer to the project's issues on GitHub for any feature requests or bug reports. ### License This project is licensed under the MIT License. --- *Source: /pip/dash_flex_layout* *Generated with dash-improve-my-llms*