FSAI Design System
Components

Popover Side Panel Hybrid

Contextual surface that floats as a popover or docks as a side panel, bridging Popover and Panel.

Overview

PopoverSidePanelHybrid is a compound primitive for contextual tool panels that can present as either a floating popover or a docked side panel.

It sits on the escalation ladder between Popover and Panel:

  • lighter than a full Panel drawer
  • more persistent and spacious than a compact Popover
  • ideal for builder tools, analytics sidecars, chat assistants, and compliance inspectors

On viewports below lg, the surface always presents as a floating panel regardless of the stored dock preference. On wider screens, users can toggle between docked and floating modes.

Compound API

PartPurpose
PopoverSidePanelHybrid.RootRoot container with open, docked, and title state.
PopoverSidePanelHybrid.TriggerClones a single child element to toggle open state.
PopoverSidePanelHybrid.DockDocked side panel slot with animated width.
PopoverSidePanelHybrid.FloatingFloating popover slot with backdrop.
usePopoverSidePanelHybridAccess open/docked state and actions inside the tree.

Basic Usage

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

const [open, setOpen] = useState(false);
const [docked, setDocked] = useState(true);

<PopoverSidePanelHybrid.Root
  open={open}
  onOpenChange={setOpen}
  docked={docked}
  onDockedChange={setDocked}
  title="Customize"
>
  <div className="flex h-screen">
    <main className="flex-1">{/* main workspace */}</main>

    <PopoverSidePanelHybrid.Dock width={360} className="border-l border-default">
      <PanelContent />
    </PopoverSidePanelHybrid.Dock>
  </div>

  <PopoverSidePanelHybrid.Floating className="max-h-[calc(100vh-5rem)] w-[380px]">
    <PanelContent />
  </PopoverSidePanelHybrid.Floating>
</PopoverSidePanelHybrid.Root>

Render the same panel content in both Dock and Floating. The hybrid switches presentation based on docked and viewport width.

With Toolbar Triggers

In builder-style UIs, triggers are often a row of IconButtons in the header rather than PopoverSidePanelHybrid.Trigger:

<IconButton
  icon="Palette"
  label="Customize"
  size="sm"
  variant="ghost"
  isActive={activePanel === 'customize'}
  onClick={() =>
    setActivePanel((current) =>
      current === 'customize' ? null : 'customize'
    )
  }
/>

Drive open from whether activePanel is set.

Props

PopoverSidePanelHybrid.Root

PropTypeDescription
openbooleanRequired. Whether the panel is open.
onOpenChange(open: boolean) => voidRequired. Called when open state changes.
dockedbooleanRequired. Whether the panel prefers docked mode.
onDockedChange(docked: boolean) => voidRequired. Called when dock preference changes.
titleReactNodeRequired. Title shown in the panel header.
showDockButtonbooleanShow the dock/pop-out toggle in the header. Defaults to true.
childrenReactNodeRequired. Dock and floating slots.

PopoverSidePanelHybrid.Trigger

PropTypeDescription
childrenReactElementRequired. Single trigger element. Receives onClick, aria-pressed, aria-expanded, and isActive.

PopoverSidePanelHybrid.Dock

PropTypeDescription
childrenReactNodeRequired. Panel content.
widthnumberRequired. Target dock width in pixels.
classNamestringAdditional classes on the dock container.
resizeHandleReactNodeOptional resize handle rendered on the dock edge.

PopoverSidePanelHybrid.Floating

PropTypeDescription
childrenReactNodeRequired. Panel content.
classNamestringAdditional classes on the floating dialog.
backdropClassNamestringClasses for the transparent backdrop overlay.

Surface Header

Both dock and floating modes share a built-in header with:

  • the title passed to Root
  • a dock/pop-out toggle button (visible on lg+ viewports, unless disabled via showDockButton={false})
  • a close button

Users can switch between docked and floating without closing the panel.

Important Conventions

  • Root must wrap both the main layout (containing Dock) and the Floating slot.
  • Below lg, docked is ignored and the panel always floats.
  • Dock animates width open and closed; content opacity fades in with the expansion.
  • Floating renders a backdrop below the header (top-[3.5rem]) so the main toolbar stays interactive.
  • Do not nest another major overlay (Modal or Panel) on top of an open hybrid panel.

Brand Dashboard And Shared Usage

PatternPathNotes
Funnel builder panelsfsai/apps/brand-dashboard/src/pages/FunnelBuilder/FunnelBuilder.tsxCanonical builder usage with header icon triggers and docked side panel.
Post composer sidecarfsai/packages/shared-ui/src/modules/socials/components/PostSets/PostComposer/PostComposer.tsxAnalytics and tooling panel in social post editing.

Guidelines

  • Do use this when a contextual tool should stay near the workspace without forcing full page navigation
  • Do render the same content in both Dock and Floating slots
  • Do persist the user's dock preference with docked / onDockedChange
  • Don't use this for simple confirmations or short forms — use Modal or Popover
  • Don't use this when the task needs a full Panel drawer with topbar, breadcrumbs, and stack management

On this page