Overlays

Popover

Floating panel anchored to a trigger, for pickers, small forms and details. Collision-aware and animated.

Installation

Install the package (React 19):

terminal
npm install @krackedui/motion

Import the styles once, in your app entry or root layout:

/src/main.tsx
import '@krackedui/motion/styles.css';

Use it anywhere inside your app's <Theme> (see Installation):

/src/PopoverExample.tsx
import { useState } from 'react';
import { Button, Popover, TextInput } from '@krackedui/motion';

export function RenamePopover() {
  const [name, setName] = useState('Roadmap');
  return (
    <Popover.Root>
      <Popover.Trigger asChild>
        <Button variant="secondary" icon="edit">Rename</Button>
      </Popover.Trigger>
      <Popover.Content width={280} aria-label="Rename page" className="flex flex-col gap-3 p-3">
        <TextInput aria-label="Page name" value={name} onChange={(e) => setName(e.target.value)} />
        <div className="flex justify-end gap-2">
          <Popover.Close asChild><Button variant="ghost">Cancel</Button></Popover.Close>
          <Popover.Close asChild><Button variant="primary">Save</Button></Popover.Close>
        </div>
      </Popover.Content>
    </Popover.Root>
  );
}

Examples

Small form

Sides

Choose a preferred side; it flips when there is not enough room.

Static surface

A popover card without positioning or behavior.

Composition

anatomy.tsx
<Popover.Root>
  <Popover.Trigger asChild>…</Popover.Trigger>   {/* or <Popover.Anchor> to position against another element */}
  <Popover.Content>
    …
    <Popover.Close asChild>…</Popover.Close>
  </Popover.Content>
</Popover.Root>

API Reference

Popover.Root

Holds the open state.

PropTypeDefault
open
boolean
defaultOpen
boolean
false
onOpenChange
(open: boolean) => void
modal
boolean
false

Popover.Trigger

The element that toggles the popover.

PropTypeDefault
asChild
boolean
false

Popover.Anchor

Optional element to position against instead of the trigger.

PropTypeDefault
asChild
boolean
false

Popover.Content

The floating panel (portalled).

PropTypeDefault
width
number
radius
"md""lg"
"md"
side
"top""right""bottom""left"
"bottom"
sideOffset
number
4
align
"start""center""end"
"start"
alignOffset
number
0
avoidCollisions
boolean
true
collisionPadding
number | Partial<Record<Side, number>>
8
onEscapeKeyDown
(event: KeyboardEvent) => void
onPointerDownOutside
(event: PointerDownOutsideEvent) => void
onCloseAutoFocus
(event: Event) => void
forceMount
true
onOpenAutoFocus
(event: Event) => void

Popover.Close

Closes the popover.

PropTypeDefault
asChild
boolean
false

PopoverSurface

Static popover card.

PropTypeDefault
width
number
radius
"md""lg"
"md"

Accessibility

  • Follows the WAI-ARIA dialog (non-modal) pattern: the content has role="dialog"; the trigger has aria-expanded and aria-controls.
  • Opening moves focus to the first focusable element inside; Tab moves within the page as usual.
  • Escape, an outside click or Popover.Close closes it, and focus returns to the trigger.
  • Give content without a visible heading an aria-label.
  • Collision-aware (8px from the viewport edges), never wider than the viewport minus 16px; scrolls when taller than the space left. Opens and closes with the shared motion layer (styles/motion.css); with prefers-reduced-motion: reduce it only fades.

Usage

  • Use for small, contextual tasks: rename, pick a date or color, adjust a filter.
  • Use Menu for a list of actions and Tooltip for a short non-interactive hint.
  • Use Dialog when the task needs full attention or has several steps.
© 2026 Motion. Internal documentation.