A Panel wraps related content, sometimes separated by borders, within a minimally-styled container.

Panel

Usage

  • Use Panel as the primary surface component for grouping related content or actions into bordered sections on a page.
  • Use Panel for content grouping on settings pages, detail views, and dashboards.
  • Use Panel to wrap data presentation elements like tables, lists, and charts.
  • Use Panel to structure form sections, especially when a page contains multiple form groups.
  • Use Card instead of Panel for smaller, self-contained surfaces used as selectable or clickable items within a grid or list. Panels and Cards are not interchangeable.
  • Maintain the Panel when loading or empty states are necessary — never remove the Panel when there is no data.
  • Compose sub-components in any arrangement; the Panel's internal grid keeps the visual structure consistent. Four common configurations:
    • Header and content — PanelHeader (with PanelTitle, optional PanelDescription, and PanelActions) above a single PanelSection. Use for settings panels, detail views, and data tables.
    • Multiple sections — PanelHeader above two or more PanelSections. Use for analytics with filter controls above a chart or table, and settings pages with separate form groups.
    • Header, content, and footer — actions moved into a PanelFooter below the content. Use for forms or multi-step flows within modals where primary actions sit at the bottom.
    • Content only — a single PanelSection with no header. Use for full-width content such as tables, authentication forms, or standalone content blocks.

Appearance

  • Enable section borders (withSectionBorders) on the Panel to add a separator between each section, making distinct content areas easier to scan. Use them to cleanly divide form sections.
  • Without borders, section padding collapses into a single gap, creating a smooth transition between content areas.
  • Use PanelInset for full-bleed content that extends edge-to-edge by ignoring the Panel's default padding — tables, images, or colored backgrounds. When placed first or last, it inherits the Panel's border radius.
  • Disable section padding (withPadding={false} on PanelSection) to let content sit flush against the edges, like an inset. Use for tables, lists, or elements that manage their own spacing.

Content

  • Write titles as short nouns or noun phrases describing what the Panel contains. Never use verbs or action-oriented titles.
  • Write descriptions that supplement the title by explaining the Panel's purpose or providing guidance. Never repeat the title.
  • Write action labels as direct verbs or verb phrases stating what happens on activation. Reinforce the label with the Panel title's noun (e.g., "Create service account" for a "Service accounts" Panel).

Implementation Notes

  • Panel is composition-based. Build Panels by passing sub-components as children: PanelHeader, PanelSection, PanelFooter, PanelInset, PanelTitle, PanelDescription, and PanelActions.
  • PanelTitle renders a Heading (defaults to level="3", color="bold"). PanelDescription renders a Paragraph (defaults to variant="secondary"). PanelActions renders a ButtonGroup with groupVariant="spaced".
  • PanelHeader and PanelFooter are specialized PanelSection wrappers with layout styling — they accept the same withBorder and withPadding props.
  • PanelSection renders a PanelInset plus padding and border classes. withPadding={false} drops the padding class, making the section behave like a bare PanelInset.
  • Setting withSectionBorders on Panel propagates through context to every descendant PanelSection, PanelHeader, and PanelFooter. Override per section with withBorder on the individual section.
  • withTabs on Panel applies a negative top margin and removes the top-left border radius to visually attach the Panel to a Tabs component above it.
  • Panel defaults to backgroundColor="base".
  • All Panel components extend Box and are polymorphic via as (default "div"; PanelTitle defaults to a heading element, PanelDescription to "p").
  • React: pass content as children. Ember: yield content in the default block, prefix component names with Pluma (<PlumaPanel>, <PlumaPanelHeader>, <PlumaPanelSection>), and pass args with @ syntax (@withSectionBorders={{true}}).

On this page