Layout Blocks¶
Layout blocks control how other blocks are arranged in the dashboard. Use them to create multi-column grids, collapsible sections, tabbed views, and visual separators.
Columns¶
Multi-column responsive grid layout. Renders children side-by-side.
Props¶
| Prop | Type | Default | Description |
|---|---|---|---|
children | list[Block] | [] | Ordered list of child blocks (one per column) |
widths | list[int] \| None | None | Relative widths (must sum to 12 for MUI grid) |
layout | "equal" \| "bento" \| "custom" | "equal" | Layout mode |
Equal Widths (Default)¶
All children get equal width:
from holysheet import Columns, KPI
Columns(children=[
KPI(label="Revenue", value="$4.64M", delta="+23%", status="positive"),
KPI(label="Deals", value=127, delta="+18", status="positive"),
KPI(label="Win Rate", value=68, unit="%", status="positive"),
])
Custom Widths¶
Use widths with values that sum to 12 (based on a 12-column MUI grid system):
from holysheet import Columns, LineChart, DataTable
Columns(
widths=[8, 4], # 2/3 + 1/3
layout="custom",
children=[
LineChart(title="Revenue Trend", data=data, x="month", y="revenue"),
DataTable(title="Summary", data=summary),
],
)
Common Width Patterns¶
| Pattern | Widths | Description |
|---|---|---|
| Two equal | [6, 6] | 50/50 split |
| Sidebar | [8, 4] | Main + sidebar |
| Sidebar left | [4, 8] | Sidebar + main |
| Three equal | [4, 4, 4] | Thirds |
| Four equal | [3, 3, 3, 3] | Quarters |
| Wide + narrow + narrow | [6, 3, 3] | Featured |
Bento Layout¶
The "bento" layout mode provides automatic sizing based on block types:
Columns(
layout="bento",
children=[
KPI(label="Revenue", value="$1.2M"),
KPI(label="Users", value="42K"),
LineChart(title="Trend", data=data, x="month", y="value"),
],
)
Nesting
Columns can contain any block type, including other Columns, Section, Tabs, and Accordion blocks for complex nested layouts.
Section¶
Grouping container that adds a heading and optional description around a collection of blocks.
Props¶
| Prop | Type | Default | Description |
|---|---|---|---|
title | str | required | Section heading |
description | str \| None | None | Optional subtitle / description |
children | list[Block] | [] | Ordered list of child blocks |
Basic Example¶
from holysheet import Section, LineChart, BarChart
Section(
title="Revenue Analytics",
description="Monthly revenue breakdown with year-over-year trends.",
children=[
LineChart(
title="Monthly Revenue vs Target",
data=revenue_data,
x="month",
y=["revenue", "target"],
),
BarChart(
title="Revenue by Region",
data=region_data,
x="region",
y="revenue",
),
],
)
Nested Sections¶
Sections can be nested for hierarchical organization:
Section(
title="Q4 Report",
children=[
Section(
title="Financial Overview",
children=[
KPI(label="Revenue", value="$4.64M"),
LineChart(title="Trend", data=data, x="month", y="revenue"),
],
),
Section(
title="Operations",
children=[
BarChart(title="Team Performance", data=team_data, x="team", y="delivered"),
],
),
],
)
Tabs¶
Tabbed content container that organizes blocks into switchable panels.
Props¶
| Prop | Type | Default | Description |
|---|---|---|---|
tabs | list[dict] | [] | List of tab definitions |
Each tab dict has:
| Key | Type | Description |
|---|---|---|
label | str | Tab label text |
children | list[Block] | Blocks to display in this tab |
Example¶
from holysheet import Tabs, LineChart, BarChart, PieChart
Tabs(tabs=[
{
"label": "📈 Revenue Trend",
"children": [
LineChart(
title="Monthly Revenue, Costs & Profit",
data=monthly_revenue,
x="month",
y=["revenue", "costs", "profit"],
height=420,
),
],
},
{
"label": "📊 By Product",
"children": [
BarChart(
title="Revenue by Product — Q3 vs Q4",
data=revenue_by_product,
x="product",
y=["q3", "q4"],
height=400,
),
],
},
{
"label": "🍩 By Segment",
"children": [
PieChart(
title="Revenue Distribution",
data=revenue_by_segment,
name="segment",
value="revenue",
),
],
},
])
Emoji Labels
Use emoji in tab labels for visual clarity: "📈 Trends", "📊 Breakdown", "🔄 Pipeline".
Multiple Blocks per Tab¶
Each tab can contain multiple blocks:
Tabs(tabs=[
{
"label": "Overview",
"children": [
Markdown(content="## Summary\n\nKey findings..."),
KPI(label="Revenue", value="$2.26M"),
LineChart(title="Trend", data=data, x="month", y="revenue"),
],
},
{
"label": "Details",
"children": [
DataTable(title="Raw Data", data=raw_data),
],
},
])
Divider¶
Visual separator line for creating visual breaks between report sections.
Props¶
| Prop | Type | Default | Description |
|---|---|---|---|
label | str \| None | None | Optional centered label text |
variant | "solid" \| "dashed" \| "dotted" | "solid" | Line style |
Examples¶
Section Separators
Labeled dividers are a great lightweight alternative to Section when you want visual separation without the full section container styling.
Accordion¶
Collapsible accordion panels for progressive disclosure of content.
Props¶
| Prop | Type | Default | Description |
|---|---|---|---|
panels | list[dict] | [] | List of panel definitions |
Each panel dict has:
| Key | Type | Description |
|---|---|---|
title | str | Panel heading |
subtitle | str (optional) | Panel subtitle |
children | list[Block] | Blocks inside the panel |
default_expanded | bool (optional) | Start expanded? Default: False |
Example¶
from holysheet import Accordion, KPI, DataTable, LineChart
Accordion(panels=[
{
"title": "Financial Overview",
"subtitle": "Revenue and cost metrics",
"default_expanded": True,
"children": [
KPI(label="Revenue", value="$2.26M", delta="+34%", status="positive"),
LineChart(title="Revenue Trend", data=revenue_data, x="month", y="revenue"),
],
},
{
"title": "Customer Data",
"subtitle": "Top accounts and health scores",
"children": [
DataTable(title="Top Accounts", data=customers_data),
],
},
{
"title": "Technical Metrics",
"children": [
KPI(label="Uptime", value="99.97%", status="positive"),
KPI(label="Response Time", value="142ms", status="neutral"),
],
},
])
Progressive Disclosure
Use Accordion to keep dashboards clean by hiding detail sections that users can expand on demand. Set default_expanded: True on the most important panel.
Compare¶
Side-by-side comparison container for placing two groups of blocks next to each other. Ideal for A/B comparisons, before/after views, and plan comparisons.
Props¶
| Prop | Type | Default | Description |
|---|---|---|---|
title | str \| None | None | Container title |
left_children | list[Block] | [] | Blocks for the left panel |
right_children | list[Block] | [] | Blocks for the right panel |
left_label | str \| None | None | Left panel header label |
right_label | str \| None | None | Right panel header label |
mode | "side_by_side" \| "overlay" | "side_by_side" | Comparison display mode |
Side-by-Side Comparison¶
from holysheet import Compare, KPI, LineChart, BarChart
Compare(
title="Q3 vs Q4 Performance",
left_label="Q3 2026",
right_label="Q4 2026",
left_children=[
KPI(label="Revenue", value="$3.1M", delta="+15%", status="positive"),
LineChart(title="Monthly Revenue", data=q3_data, x="month", y="revenue"),
],
right_children=[
KPI(label="Revenue", value="$4.2M", delta="+22%", status="positive"),
LineChart(title="Monthly Revenue", data=q4_data, x="month", y="revenue"),
],
)
Plan Comparison¶
from holysheet import Compare, Markdown
Compare(
title="Pricing Plans",
left_label="Starter — $29/mo",
right_label="Enterprise — $199/mo",
left_children=[
Markdown(content="""
- ✅ 5 reports/month
- ✅ 3 themes
- ❌ Custom themes
- ❌ Password protection
- ❌ API access
"""),
],
right_children=[
Markdown(content="""
- ✅ Unlimited reports
- ✅ All themes
- ✅ Custom themes
- ✅ Password protection
- ✅ API access
"""),
],
)
Compare vs Columns
Compare is similar to Columns(widths=[6, 6]) but adds dedicated labels for each side and visual styling that emphasizes the comparison context. Use Columns for general side-by-side layout, and Compare when you want to explicitly highlight differences between two groups.
Layout Patterns¶
Full Dashboard Layout¶
from holysheet import (
Report, KPI, Columns, Section, Tabs, Divider,
LineChart, BarChart, PieChart, DataTable, Markdown,
)
report = Report(title="Dashboard", theme="dark")
# Hero section
report.add(Markdown(content="## Executive Summary\n\nKey findings..."))
# KPI row
report.add(Columns(children=[
KPI(label="Revenue", value="$4.64M", delta="+23%", status="positive"),
KPI(label="Deals", value=127, delta="+18", status="positive"),
KPI(label="Win Rate", value="68%", delta="+4.2%", status="positive"),
]))
report.add(Divider(label="Detailed Analysis"))
# Charts in tabs within a section
report.add(Section(
title="Revenue Analytics",
children=[
Tabs(tabs=[
{"label": "📈 Trends", "children": [
LineChart(title="Monthly Revenue", data=data, x="month", y="revenue"),
]},
{"label": "📊 Breakdown", "children": [
BarChart(title="By Region", data=region_data, x="region", y="sales"),
]},
]),
],
))
# Side-by-side charts
report.add(Columns(children=[
PieChart(title="Revenue Split", data=segment_data, name="segment", value="revenue"),
DataTable(title="Top Deals", data=deals_data),
]))
report.export_html("dashboard.html")