Full documentation: https://flexlayout.2plot.dev — the dedicated flexlayout-dash documentation site, with the complete API reference and deeper examples. This page is the quick-start overview.
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
⭐️ Star this component on GitHub! Stay up to date on new releases and browse the codebase.
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.
# File: docs/flexlayout_dash/introduction.py
"""
Dash Flex Layout - Quick Start Example
======================================
A simple two-panel layout with resizable divider.
"""
import dash_mantine_components as dmc
import flexlayout_dash 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.
import flexlayout_dash 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.
# File: docs/flexlayout_dash/two_panel_layout.py
"""
Dash Flex Layout - Multiple Tabs Example
=========================================
Single tabset with multiple tabs for navigation.
"""
import dash_mantine_components as dmc
import flexlayout_dash 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: 0in tabset to choose initially selected tab (zero-indexed) - Enable
tabEnableFloat: Trueto allow tabs to be popped out into floating windows - Each tab needs a unique
idthat matches a Tab component
Vertical Layouts
Use "type": "column" to create vertical splits with top/bottom panels.
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.
# File: docs/flexlayout_dash/ide_layout.py
"""
Dash Flex Layout - Nested Layout Example
==========================================
Simple nested layout demonstrating rows within columns.
"""
import dash_mantine_components as dmc
import flexlayout_dash 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:
model = {
"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.
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.
# File: docs/flexlayout_dash/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 flexlayout_dash 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"orcolorScheme="dark"prop - Liquid Glass Themes: Available via custom CSS (see assets/flexlayout-dock.css)
Custom 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.
# File: docs/flexlayout_dash/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 flexlayout_dash 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
model = {
"global": {
"tabEnableRenderOnDemand": False, # Required for callbacks!
},
# ...the rest of the model (layout, borders)...
}
Without this setting, tabs are unmounted when not visible, causing callbacks to fail.
Callback Best Practices:
- Use
useStateForModel=Trueto avoid excessive callback triggers - Define all chart/component types upfront, toggle visibility with styles
- Don't dynamically replace
childrenin 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:
model = {
"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:
model = {
"layout": {
"type": "row", # "row" (horizontal) or "column" (vertical)
"weight": 100, # Relative size percentage
"children": [...] # Array of tabsets or nested layouts
},
}
Tabset:
{
"type": "tabset",
"weight": 50, # 50% of parent width/height
"selected": 0, # Initially selected tab index
"children": [...] # Array of tab objects
}
Tab:
{
"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: Falsein global config - Use
useStateForModel=Trueto 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
colorSchemeprop only to force specific theme - Apply custom CSS to
.flexlayout__layoutclass - Test both light and dark modes
Troubleshooting
Callbacks Not Firing:
- Ensure
tabEnableRenderOnDemand: Falsein 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"}orh="500px"
Tabs Not Appearing:
- Check that Tab component
idmatches tabidin 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.
Note for AI agents: This is the static, prerendered view of an interactive Dash application served because we detected a non-JS user agent. Full prose docs:
- /pip/dash_flex_layout/llms.txt — LLM-friendly documentation
- /sitemap.xml
- /robots.txt