sdxc

Type to search, or start from one of these:

Popover

A floating surface anchored to whatever element opened it, built entirely on the native Popover API.

Filter results

Retention

Search reaches back ninety days on this plan. Older records stay exportable.

View code
<Button commandfor="result-filters" command="toggle-popover" variant="outline">
	<SlidersHorizontalIcon />
	Filters
</Button>

<Popover id="result-filters" placement="bottom">
	{/* The surface brings a border, a radius and a shadow; the panel inside brings its
	    own padding, so a menu can still run its rows to the edge. */}
	<div mix={[vstack({ gap: 4, align: "stretch" }), p(4)]}>
		<Header mix={[m(0)]}>Filter results</Header>

		<div mix={[vstack({ gap: 2, align: "stretch" })]}>
			<Label htmlFor="filter-query">Contains</Label>
			<Input id="filter-query" name="query" placeholder="middleware" />
		</div>

		<div mix={[hstack({ gap: 2, align: "end" })]}>
			<div mix={[vstack({ gap: 2, align: "stretch" })]}>
				<Label htmlFor="filter-from">From</Label>
				<Input id="filter-from" name="from" type="date" />
			</div>
			<div mix={[vstack({ gap: 2, align: "stretch" })]}>
				<Label htmlFor="filter-to">To</Label>
				<Input id="filter-to" name="to" type="date" />
			</div>
		</div>

		<Label mix={[hstack({ gap: 2, align: "center" })]}>
			<input type="checkbox" name="archived" />
			Include archived
		</Label>

		<Separator />

		<div mix={[hstack({ gap: 2, justify: "end" })]}>
			<Button commandfor="result-filters" command="hide-popover" variant="ghost" size="sm">
				Cancel
			</Button>
			<Button type="submit" size="sm">
				Apply
			</Button>
		</div>
	</div>
</Popover>

<Button commandfor="retention-note" command="toggle-popover" variant="outline">
	<InfoIcon />
	Why is this limited?
</Button>

{/* "manual" keeps the panel open through an outside click, so a reader can go on
    working with the page while it stays on screen. */}
<Popover id="retention-note" placement="top">
	<div mix={[vstack({ gap: 3, align: "start" }), p(4)]}>
		<p mix={[m(0), text("sm"), weight("medium")]}>Retention</p>
		<p mix={[m(0), text("sm")]}>
			Search reaches back ninety days on this plan. Older records stay exportable.
		</p>
		<Button commandfor="retention-note" command="hide-popover" variant="outline" size="sm">
			Got it
		</Button>
	</div>
</Popover>

Installation

An ordinary dependency: install it, import the theme once, and import the component where it is used.

npm add @sdxc/ui
import "@sdxc/ui/theme.css";

Usage

import { Popover } from "@sdxc/ui";

Renders the floating surface itself: a popover-attributed <div> positioned via CSS anchor positioning. The invoker that opens it becomes the implicit anchor its position-area resolves against.

Examples

<Popover id="filters" placement="top" mix={[fade({ duration: durations.normal })]}>
	<OverlayArrow placement="top">
		<svg width={12} height={12} viewBox="0 0 12 12">
			<path d="M0 0 L6 6 L12 0" />
		</svg>
	</OverlayArrow>
	{content}
</Popover>

Props

Read from the component's own types, so every prop, every default and every allowed value is listed.

PropTypeDescription
idstringStable id an invoker elsewhere on the page targets to open this host.
popover?"auto" | "hint" | "manual"popover attribute mode: "auto" dismisses on outside click or Escape and closes sibling "auto" popovers when shown; "hint" layers over an open one without closing it; "manual" closes only when hidden explicitly.
placement?"top" | "top-start" | "top-end" | "bottom" | "bottom-start" | "bottom-end" | "left" | "left-start" | "left-end" | "right" | "right-start" | "right-end"Side of the anchor to render against. Defaults to DEFAULT_PLACEMENT.
childrenRemixNodeThe popover's content.

Also accepts everything in Omit<TagProps<"div">, "id" | "popover">.

Types

NameValuesWhat it decides
Placement"top" | "top-start" | "top-end" | "bottom" | "bottom-start" | "bottom-end" | "left" | "left-start" | "left-end" | "right" | "right-start" | "right-end"Side of the anchor the host renders against, and, for the four corner variants, which anchor edge it aligns to along the perpendicular axis.