Selection Frame
ResizeObserver, so it always fits whatever it wraps, even when the content changes size. Choose square or circle handles, a solid, dashed or long-dash stroke, override the dash pattern directly, and turn on animated for marching ants with handles that pop in. Everything respects prefers-reduced-motion.Selection Frame
Wrap any span or block — the frame measures it and fits.
padding- is the gap in pixels between the content and the frame.
6here; the default is4.
Installation
New project? Follow the installation guide to set up Tailwind CSS, shadcn, the cn helper and lucide-react, register the @algorize-ui registry once, then copy your styles from the Themes page.
Install Selection Frame
components/ is written into your project. Copy any snippet from a Usage tab above and it runs.
Install dependencies
Nothing beyond the shared setup — Selection Frame needs only the cn helper and lucide-react, which the installation guide already put in place.
Examples
Handles
handles- picks the corner shape —
"square"(default, 7px) or"circle"(8px). Both fill with the page background so they read as cut-outs on the stroke.
Lines
line- is the stroke style —
"solid"(default),"dashed"(dash[4, 4]) or"long"(dash[10, 6]). dash- overrides the
[dash, gap]pixel pair of either preset —[1, 3]in the last frame gives a dotted stroke.
Animated
Hit Reset on the preview to replay the handle pop-in.
animated- turns a
dashedorlongstroke into marching ants and springs the four handles in on mount. A solid stroke only gets the handle animation. Both are skipped underprefers-reduced-motion. color- is the accent — any CSS colour. The second frame is pinned to
#e11d48so you can see it override the page colour.
Inline in text
inline- is
trueby default, so the frame renders as an inline-block and sits inside a sentence like any other word.
Block & radius
Drag the sliders — the frame re-measures and redraws live.
- Set
inline{false} - to make the frame block-level so it can wrap a card, image or layout element and take the full width you give it via
className. radius- rounds the frame's corners in pixels. The handles stay pinned to the true corner points.
Features
Measures live
A ResizeObserver tracks the child, so the frame re-fits when text reflows, fonts load or the content changes.
Pixel-accurate
The stroke is centred on the frame edge and each handle is centred on the true corner point, so nothing sits a fraction of a pixel off.
Respects reduced motion
Marching ants are an indefinite loop, so both the march and the handle spring are disabled when the visitor prefers reduced motion.
Decorative only
The SVG and handles are aria-hidden and ignore pointer events — your content stays exactly as readable and clickable as before.
Best Practices & Guidelines
Give the frame room
The stroke and handles are drawn outside the child by padding pixels (plus half a handle). Leave that much space around the wrapper — an overflow-hidden parent will clip the corners.
Use marching ants sparingly
An endless animation pulls the eye. Reserve animated for the one element on screen you actually want people to look at.
Props Reference
<SelectionFrame> Props
| Prop | Type | Default | Description |
|---|---|---|---|
children | React.ReactNode | Required | The content to frame; measured live. |
handles | "square" | "circle" | "square" | Corner handle shape. |
line | "solid" | "dashed" | "long" | "solid" | Stroke style. dashed resolves to dash [4, 4], long to [10, 6]. |
dash | [number, number] | — | Overrides the [dash, gap] px pair for "dashed" / "long". |
animated | boolean | false | Marching ants for "dashed" / "long"; handles always animate in. Disabled under prefers-reduced-motion. |
color | string | "var(--primary)" | Accent colour. Any CSS colour or theme variable. |
radius | number | 0 | Frame corner radius in pixels. |
padding | number | 4 | Gap in pixels between the content and the frame. |
inline | boolean | true | Inline (for text spans) vs block-level. |
className | string | — | Extra classes for the outer wrapper — e.g. a width when inline is false. |