Modals are overlay dialogs with their own rows of layouts and visuals — drill-down detail without leaving the page. They are defined globally on the report and triggered from visuals.
report.add_modal(id, title, description=None) returns a Modal; build its
content with add_row() exactly like a page:
modal = report.add_modal("revenue-details", "Revenue Breakdown",
description="Detailed view of revenue by region.")
modal.add_row().add_table("regionalRevenue", title="Regional Data")Any visual or layout accepts modal_id (a common prop).
Hovering the element shows an expand icon in the top-right corner; clicking
it opens the modal:
page.add_row().add_kpi("kpiData", "Revenue", title="Total Revenue",
modal_id="revenue-details")2. Dedicated button — ModalButton
from dl2_reports import ModalButton
page.add_row(ModalButton("revenue-details", "View Detailed Breakdown"))Double-clicking a table or checklist row (or right-click → Open details) opens a detail modal. Calendar events (dl2 0.5+) use the same API — double-click an event.
Two flavors:
Built-in — row_modal=True renders a simple field list; customize with
row_modal_columns and row_modal_title:
row.add_table("orders", row_modal=True,
row_modal_columns=["Region", "Rep", "Amount"],
row_modal_title="Order")Custom — row_modal_id="..." opens one of your global modals instead.
Cards inside it can reference the clicked row through
{{ row.ColumnName }} templates:
row.add_table("orders", row_modal_id="order-detail")
modal = report.add_modal("order-detail", "Order Details")
modal.add_row().add_card(
title="Order — {{ row.Region }}",
text="**Rep:** {{ row.Rep }}\n**Amount:** {{ formatCurrency(row.Amount) }}",
content_type="md",
)Column formats apply inside row detail modals too.
- Modal
ids must be unique; the viewer validator warns about unknownmodalId/rowModalIdreferences. - Modals are global — several visuals can trigger the same modal.
- A modal's rows support everything a page's rows do: layouts, tabs, charts, tables.
- Modal button · Card templates · Table · Link (navigation instead of overlay)