FSAI Design System
Components

Popover

Floating panel primitive for filters, menus, custom pickers, and lightweight inline workflows.

Overview

Popover is the shared floating-panel primitive used across shared UI and the brand dashboard.

It is the low-level building block behind many compact interactive surfaces such as:

  • filter popovers
  • toolbar popovers
  • custom date pickers
  • inline entity managers

Use Popover when the interaction needs a contextual floating panel anchored to a trigger. For ordinary dropdown selection, prefer higher-level components such as Select, AutocompleteSelect, or Menu when they already fit.

Compound API

PartPurpose
PopoverRoot container.
Popover.TriggerUses an existing element as the trigger.
Popover.ButtonShared built-in popover trigger button.
Popover.PanelFloating panel surface.
usePopoverAccesses isOpen, open, close, and toggle inside a popover tree.

Basic Usage

<Popover placement="bottom-start" offset={8}>
  <Popover.Button leftAdornment="CalendarDays">
    Choose Date
  </Popover.Button>
  <Popover.Panel className="w-64 p-2">
    <DateSelector selected={selectedDate} onSelect={setSelectedDate} />
  </Popover.Panel>
</Popover>

With A Custom Trigger

Use Popover.Trigger when the anchor should be an existing component such as IconButton.

<Popover placement="bottom-start">
  <Popover.Trigger>
    <IconButton icon="Filter" label="Filters" />
  </Popover.Trigger>
  <Popover.Panel className="max-h-96 overflow-auto">
    {/* panel content */}
  </Popover.Panel>
</Popover>

This is the same pattern used by shared DataTablePopover.

Closing From Panel Content

Popover.Panel supports a render prop so panel actions can call close().

<Popover>
  <Popover.Button>Bulk Actions</Popover.Button>
  <Popover.Panel>
    {({ close }) => (
      <div className="p-2">
        <Button role="button" size="sm" onClick={() => { applyAction(); close(); }}>
          Apply
        </Button>
      </div>
    )}
  </Popover.Panel>
</Popover>

Root Render Prop

Popover itself also supports a render prop:

<Popover>
  {({ isOpen, close }) => (
    <>
      <Popover.Button>{isOpen ? 'Open' : 'Closed'}</Popover.Button>
      <Popover.Panel>{/* ... */}</Popover.Panel>
    </>
  )}
</Popover>

This is useful when trigger or surrounding UI needs access to isOpen or close without manually using usePopover.

Props

Popover

PropTypeDefaultDescription
childrenReactNode | ({ isOpen, close }) => ReactNodeRequired. Popover contents.
offsetnumber8Space between trigger and panel.
placementPlacement'bottom-start'Floating UI placement.
onClose() => voidCalled when the popover closes.

Popover.Trigger

PropTypeDescription
childrenReactElementRequired. Single trigger element.

Popover.Button

PropTypeDefaultDescription
childrenReactNodeButton content.
variant'default' | 'ghost''default'Trigger style variant.
size'lg' | 'md' | 'sm' | 'xs''md'Trigger size.
classNamestringAdditional classes.
leftAdornmentIconNameOptional left icon.
rightAdornmentIconNameOptional right icon.
disabledbooleanDisables interaction.

Popover.Panel

PropTypeDescription
childrenReactNode | ({ isOpen, close }) => ReactNodePanel content or render prop.
classNamestringAdditional panel classes.

Important Conventions

  • Popover.Trigger must receive a single element that can accept a ref.
  • Prefer Popover.Button when the trigger is just a normal design-system button.
  • Prefer the Popover.Panel render prop when panel actions should close the popover after acting.
  • Popover supports nested popovers, so you do not need to invent a separate floating-state pattern for nested menus.

Brand Dashboard And Shared Usage

PatternPathNotes
Shared toolbar/filter popoverfsai/packages/shared-ui/src/components/DataTable/toolbar/Popover.tsxCanonical IconButton + Popover.Trigger composition.
Inline entity manager compositionfsai/packages/shared-ui/src/components/InlineEntityManager/InlineEntityManager.primitives.tsxUses usePopover() for local open/close behavior.
Rich text editor popoversfsai/apps/brand-dashboard/src/components/RichTextEditor/RichTextEditor.tsxFloating formatting controls anchored to toolbar buttons.
Portal-editor section pickerfsai/apps/brand-dashboard/src/pages/PortalEditor/components/AddSectionPopover/AddSectionPopover.tsxProduct-facing creation popover with permission gating.

Guidelines

  • Do use Popover for compact anchored workflows and utilities
  • Do use higher-level components first when they already cover the interaction
  • Do use Popover.Trigger with IconButton for toolbar actions
  • Don't use Popover as a replacement for Modal or Panel

On this page