Popover
A small panel about the control that opened it. It docks to the trigger and shares its edge, so the two read as one shape. It holds a quick edit or a few settings; the page around it stays live, and a click outside or Escape puts it away.
Loading the live example…
"use client"
import { useState } from "react"
import { Button } from "@/components/keyline/ui/button"
import { Field, FieldFrame, FieldLabel, FieldTextarea } from "@/components/keyline/ui/field"
import { Popover, PopoverBody, PopoverClose, PopoverContent, PopoverFooter, PopoverHeader, PopoverTrigger } from "@/components/keyline/ui/popover"
export function DeliveryNote() {
const [note, setNote] = useState("Loading dock is round the back.")
const [draft, setDraft] = useState(note)
return (
<div className="grid gap-3 text-[14px]">
<div className="flex flex-wrap items-center gap-3">
<span>
<span className="font-kl-mono text-[13px]">DM-4107</span> · Lackawanna County
</span>
<Popover onOpenChange={(o) => o && setDraft(note)}>
<PopoverTrigger render={<Button size="compact" />}>Delivery note</PopoverTrigger>
<PopoverContent className="w-[min(340px,calc(100vw-24px))]">
<PopoverHeader title="Delivery note" description="Darryl reads it before he loads the truck." />
<PopoverBody>
<Field>
<FieldLabel className="sr-only">Note</FieldLabel>
<FieldFrame>
<FieldTextarea rows={3} value={draft} onChange={(e) => setDraft(e.target.value)} />
</FieldFrame>
</Field>
</PopoverBody>
<PopoverFooter>
<PopoverClose render={<Button layout="cell" />}>Cancel</PopoverClose>
<PopoverClose render={<Button layout="cell" variant="primary" onClick={() => setNote(draft.trim())} />}>Save note</PopoverClose>
</PopoverFooter>
</PopoverContent>
</Popover>
</div>
<p role="status" className="m-0 text-kl-ink-2">
{note ? `Note: ${note}` : "No delivery note."}
</p>
</div>
)
}Installation
npx shadcn@latest add @keyline-ui/popoverRun it where your components.json is. The first time, map the @keyline-ui registry: one command, in Installation.
Usage
import { Popover, PopoverBody, PopoverClose, PopoverContent, PopoverFooter, PopoverHeader, PopoverTrigger } from "@/components/keyline/ui/popover"<Popover>
<PopoverTrigger render={<Button size="compact" />}>Delivery note</PopoverTrigger>
<PopoverContent>
<PopoverHeader title="Delivery note" description="…" />
<PopoverBody>…</PopoverBody>
<PopoverFooter>
<PopoverClose render={<Button layout="cell" />}>Cancel</PopoverClose>
</PopoverFooter>
</PopoverContent>
</Popover>Props
| Prop | Type | Default | Description |
|---|---|---|---|
side · align | Base UI side · align | Default "bottom" · "start" | On PopoverContent: where it docks. It flips when there's no room. |
attachWeight | 1 | 2 | 3 | Default 2 | The trigger's edge weight, so the shared edge matches: 1 for a cell, 2 for a control. |
detached | boolean | Default false | Sits one gutter away in its own frame, for content not about the trigger. |
anchor | Element | ref | Default the trigger | Docks to another element. |
PopoverHeader | { title, description?, close?, closeLabel? } | Default — | A header row with a close cell. |
Built on Base UI Popover; its other props pass through.