Panels
CdxSlideInPanel is the canonical drawer / detail panel for CDX. It slides in from the right (default), left, or bottom — and hosts an inner navigator so you can drill into nested pages without stacking modal routes on the root navigator.
Open a single page
CdxSlideInPanel.show<bool>(
context: context,
panel: CdxSlideInPanel(
title: 'Edit area',
icon: FluentIcons.edit_24_regular,
width: const PanelDimension.clamped(fraction: 0.7, min: 540, max: 820),
content: AreaEditor(area: area),
actions: [
DialogAction.cancel(onPressed: () => Navigator.of(context).pop(false)),
DialogAction.primary(label: 'Save', onPressed: () => Navigator.of(context).pop(true)),
],
),
);show<T> is a wrapper around showGeneralDialog (or showModalBottomSheet on compact viewports — see responsiveBottomSheet below).
Page mode (recommended for nested flows)
For nested navigation, pass initialPage and use CdxPanelPage.push inside its content:
CdxSlideInPanel.show(
context: context,
panel: CdxSlideInPanel(
width: const PanelDimension.clamped(fraction: 0.7, min: 540, max: 820),
initialPage: CdxPanelPage(
title: 'Areas',
icon: FluentIcons.building_factory_24_regular,
content: AreasMaster(onSelect: (area) => CdxPanelPage.push(
context: context,
page: CdxPanelPage(
title: area.name,
content: AreaDetail(area: area),
actions: [DialogAction.primary(label: 'Save', onPressed: ...)],
),
)),
),
),
);The pushed page slides in within the panel's bounds (not over the entire screen). The auto-derived dismiss button shows a back arrow on pushed pages and a close X on the root page.
CdxPanelPage
A page hosted inside the inner navigator. Mirrors DialogShell's header / content / footer API.
CdxPanelPage(
title: 'Audit Trail',
icon: FluentIcons.history_24_regular,
content: AuditList(),
headerActions: [Button.icon(icon: FluentIcons.arrow_download_24_regular, ...)],
footerMessage: const DialogMessage(text: 'Last refreshed 2 minutes ago.', severity: MessageSeverity.info),
actions: [DialogAction.cancel(label: 'Close', onPressed: () => Navigator.of(context).pop())],
)CdxPanelPage.push<T> returns the value passed to Navigator.pop from inside the pushed page — same contract as Navigator.push.
PanelDimension
Sizing primitive for the panel's width (and bottom-direction height).
PanelDimension.size(720) // absolute
PanelDimension.fraction(0.6) // 60% of viewport
PanelDimension.clamped(fraction: 0.7, min: 540, max: 820) // common — fluid + boundedSlideInDirection
enum SlideInDirection { right, left, bottom }Right (default) pairs with the page-content layout that puts the primary action on the right. bottom always uses full screen width and defaults to 85% of viewport height.
Responsive bottom sheet
CdxSlideInPanel.show(
...,
responsiveBottomSheet: true, // default
compactBreakpoint: 900,
);When the viewport is narrower than compactBreakpoint AND responsiveBottomSheet is true, the panel is shown as a showModalBottomSheet instead — gives mobile-style UX automatically. Set responsiveBottomSheet: false to always use the slide-in panel regardless of viewport.
Panel-aware navigation
When a button inside a panel needs to navigate the main app via go_router, call context.dismissAndGo instead of context.go — it walks up the panel stack and dismisses every enclosing CdxSlideInPanel before firing the navigation. Without this, the panel stays mounted on top of the destination page.
// inside any widget hosted in a panel:
context.dismissAndGo('/areas/${area.id}');
context.dismissAndPush<bool>('/areas/${area.id}/audit');The extension lives at CdxSlideInPanelNavigation on BuildContext — both methods are safe to call unconditionally (no-op outside any panel), so callers don't need to guard with a maybeOf check.
Manual dismiss
CdxSlideInPanel.dismiss(context, result); // pop the nearest enclosing panel
CdxSlideInPanel.dismissAll(context); // pop every enclosing panel (drill-out)