FSAI Design System
Components

Panel

Right-side detail drawer used for master-detail workflows, editors, and deep object inspection.

Overview

Panel is the shared-ui right-side drawer primitive used throughout the brand dashboard for detail views, editors, and workflow configuration.

It is a compound component exported from @fsai/shared-ui and built on top of Headless UI Dialog plus shared layout primitives. In practice it supports two main patterns:

  1. A global stack-managed panel shell, where the app opens one Panel and individual screens return only Panel.Content
  2. A feature-owned panel, where the feature renders the full Panel tree itself

For most detail experiences in the dashboard, Panel is the standard container.

Basic Usage

Use the full Panel tree when the feature owns its own open/close state:

import { Panel } from '@fsai/shared-ui';

<Panel isOpen={isOpen} handleClose={() => setIsOpen(false)}>
  <Panel.Backdrop />
  <Panel.Popup size="lg">
    <Panel.Content>
      <Panel.Topbar>
        <Panel.Topbar.Left>
          <Panel.Close />
        </Panel.Topbar.Left>
      </Panel.Topbar>

      <Panel.Header>
        <Panel.Header.Left>
          <Panel.Header.LeftContent>
            <Panel.Header.Title>Edit Workflow Node</Panel.Header.Title>
            <Panel.Header.Description>
              Configure how this step behaves.
            </Panel.Header.Description>
          </Panel.Header.LeftContent>
        </Panel.Header.Left>
      </Panel.Header>

      <Panel.Body>
        <Panel.Section>{/* panel content */}</Panel.Section>
      </Panel.Body>
    </Panel.Content>
  </Panel.Popup>
</Panel>

Stack-Managed Usage

In the brand dashboard, many entity panels are rendered inside a shared global shell owned by PanelStack. In that case, the panel content component should return Panel.Content and related subcomponents only.

import { Panel, Breadcrumb } from '@fsai/shared-ui';

function LeadPanel() {
  return (
    <Panel.Content>
      <Panel.Topbar>
        <Panel.Topbar.Left>
          <Panel.Close />
          <Breadcrumb items={items} />
        </Panel.Topbar.Left>
      </Panel.Topbar>

      <Panel.Header>
        <Panel.Header.Left>
          <Panel.Header.Avatar name={lead.name} icon="User" />
          <Panel.Header.LeftContent>
            <Panel.Header.Title>{lead.name}</Panel.Header.Title>
            <Panel.Header.Description leftAdornment="PinLocation">
              {lead.city}
            </Panel.Header.Description>
          </Panel.Header.LeftContent>
        </Panel.Header.Left>
      </Panel.Header>

      <Panel.Body>
        <Panel.Section>{/* tabs, details, activity */}</Panel.Section>
      </Panel.Body>
    </Panel.Content>
  );
}

Do not nest a second Panel inside PanelStack.

Sizes And Behavior

Panel.Popup sizeDesktop target widthTypical usage
md672pxFocused forms, node configuration, compact editors
lg896pxStandard entity detail panels
xl1152pxRicher detail panels with more horizontal layout
fullviewport-drivenLarge workflows, project views, immersive editing

Behavior:

  • Desktop panels slide in from the right and are resizable from the left edge.
  • Mobile panels switch to a full-viewport presentation.
  • full is not literally the whole desktop viewport; it uses the available viewport width with layout offsets.
  • Panel.Topbar sticky keeps the top bar pinned while the body scrolls.

Compound API

Root

PartPurpose
PanelRoot dialog container. Requires isOpen and handleClose.
Panel.BackdropShared backdrop overlay.
Panel.PopupAnimated drawer shell. Accepts size and className.

Top Bar

PartPurpose
Panel.TopbarTop row for close, breadcrumb, actions, and context controls.
Panel.Topbar.LeftLeft-aligned controls, usually Panel.Close and Breadcrumb.
Panel.Topbar.RightRight-aligned actions such as menus or share controls.
Panel.CloseStandard close button wired to panel context.
Panel.CopyLinkCopies the current URL or a provided link.
Panel.MenuStandard overflow action menu.
Panel.Menu.ItemSmall menu item sized for panel actions.
Panel.Menu.ItemWithConfirmationDestructive or high-risk action with confirmation.
Panel.ToggleFavoriteFavorite toggle action button.

Content Layout

PartPurpose
Panel.ContentPrimary vertical layout wrapper for panel internals.
Panel.HeaderMain entity header block below the top bar.
Panel.Header.LeftLeft side of the entity header.
Panel.Header.LeftContentTitle and description stack.
Panel.Header.RightRight-side controls or metadata.
Panel.Header.TitlePrimary panel title. Supports loading skeleton state.
Panel.Header.DescriptionSecondary description line, optionally with leftAdornment.
Panel.Header.AvatarStandard entity avatar block.
Panel.Header.MetaCompact metadata row.
Panel.BodyScrollable main body region.
Panel.SectionHorizontal content padding block.
Panel.ErrorGuardPanel-tuned ErrorGuard with centered error-state spacing.

Props

Panel

PropTypeDefaultDescription
isOpenbooleanRequired. Controls whether the panel is mounted and visible.
handleClose() => voidRequired. Called when the panel should close.
childrenReactNodeRequired. Usually Panel.Backdrop and Panel.Popup.

Panel.Popup

PropTypeDefaultDescription
size'md' | 'lg' | 'xl' | 'full'Required. Width preset for the panel shell.
classNamestringAdditional layout or spacing classes.
childrenReactNodeRequired. Usually Panel.Content or a custom layout.

Panel.Topbar

PropTypeDefaultDescription
stickybooleanfalseKeeps the top bar pinned while content scrolls.
classNamestringAdditional layout or spacing classes.
childrenReactNodeRequired. Top bar content.

Common Composition Patterns

Entity Detail Panel

Common in lead, location, task, franchisee, and finder-result panels:

  • Panel.Topbar with Panel.Close, breadcrumb, Panel.CopyLink, and Panel.Menu
  • Panel.Header with avatar, title, description, and right-side metadata
  • Panel.Section for summary cards, tags, or details
  • Tabs or scrollable content below

Workflow Or Editor Panel

Common in workflow builders and editor-style experiences:

  • Feature owns the full Panel tree
  • Panel.Popup size="md" or size="lg"
  • top bar actions are usually menu-driven
  • body content may skip Panel.Header entirely if the screen uses a custom layout

Full-Width Operational Panel

Used when the panel is effectively a secondary workspace:

  • Panel.Popup size="full"
  • Panel.Content className="overflow-auto" or Panel.Body for controlled scrolling
  • Often used for complex editing or deep operational workflows

Error Recovery In Panels

When panel content fails to load, prefer Panel.ErrorGuard over hand-rolling spacing around ErrorState.

Panel.ErrorGuard standardizes the most common panel fallback layout:

  • min-h-full justify-center px-6 py-12
  • centered messaging within Panel.Body
  • shared ErrorGuard preset behavior

In stack-managed panels, the typical recovery actions are Back and Close Panel, not a generic full-page reload.

Brand Dashboard Usage Patterns

Representative usages that define the expected patterns:

PatternPathNotes
Global shellfsai/apps/brand-dashboard/src/components/PanelStack/PanelStack.tsxOwns the main Panel, backdrop, size mapping, and active panel rendering.
Content-only entity panelfsai/apps/brand-dashboard/src/pages/Marketing/MarketingLeadPanel.tsxShows the standard topbar + header + section + tabs composition.
Content-only operational panelfsai/apps/brand-dashboard/src/pages/Workflows/WorkflowRunPanel.tsxUses Panel.Content, Panel.Topbar, and Panel.Body inside the global shell.
Feature-owned local panelfsai/apps/brand-dashboard/src/pages/Workflows/components/config-panel/NodeConfigPanel.tsxRenders the full Panel tree for a workflow configuration drawer.
Full-size editor panelfsai/apps/brand-dashboard/src/pages/AdminPanel/Helpdesk/ArticleManagementPage.tsxUses a large panel as an editor workspace.

Important Conventions

  • Use Panel for right-side detail and editing workflows, not for small confirmations or simple overlays. Use Modal for centered dialogs.
  • If a view is rendered inside PanelStack, return Panel.Content and related subcomponents only. Do not create a nested Panel.
  • Panel.Close and other context-dependent helpers require a real Panel root above them.
  • Prefer Panel.ErrorGuard when the panel body needs an error fallback.
  • Panel may sit below a Modal, but a Panel must never open on top of an active Modal.
  • Anchored floating components such as Popover, Menu, Picker, and Tooltip can still open inside the current Panel or Modal; this rule only applies to major overlay surfaces.
  • Prefer Panel.Body for the main scroll container rather than letting the entire drawer scroll unpredictably.
  • Use Panel.Section to keep horizontal padding consistent.
  • Use the size presets instead of hardcoding widths.

Naming Collision

There is also a local file at fsai/apps/brand-dashboard/src/modules/library/components/FileViewer/Panel.tsx that defines a different Panel layout component. It is unrelated to @fsai/shared-ui's drawer primitive.

When documenting or generating code, distinguish between:

  • import { Panel } from '@fsai/shared-ui'
  • import { Panel } from './Panel'

Guidelines

  • Do use Panel as the default container for master-detail views in the dashboard
  • Do use Panel.Topbar for close, breadcrumbs, and high-level actions
  • Do use Panel.Header for entity identity and top-level metadata
  • Do use Panel.ErrorGuard for centered panel failure states
  • Do use Panel.Body when content should scroll independently of the shell
  • Do choose size="full" only when the panel needs workspace-like breadth
  • Don't nest Panel inside the global PanelStack
  • Don't open a Panel on top of an active Modal
  • Don't use Panel for simple confirmations or short forms that should be a modal
  • Don't bypass the shared close/menu/header primitives unless the feature genuinely needs a custom layout

On this page