VI Controls

Star on GitHubFeedback
VI ControlsNative HTMLot-picks

Picks

A list of choices that carry their own content. The one you took turns italic, and either a dot slides to it along a plucked string its initial hangs in the margin like a rubricated capital, its name lies faint behind the list, or two registration crosses mark its corners.

Report an issue with Picks

Example

Pair
Ink
Paper
Format
Pizzicato
Pointed at
Focus
Chosen
Disabled
Rubric
Pointed at
Chosen
No capitals
Disabled
Watermark
Register
Pointed at
Chosen

Install

Run it in a project that has the shadcn CLI set up. It brings the 0nlyType base along.

npx shadcn@latest add https://thedirectors.agency/ui/r/picks.json

Usage

picks-example.tsx
import { Pick, PickDescription, Picks, PickTitle } from "@/components/ui/picks"export default function Example() {return (<div className="grid items-start gap-x-(--ot-space-8) gap-y-(--ot-space-7) md:grid-cols-2"><Picks legend="Pair" defaultValue="press"><Pick value="parma"><PickTitle>Parma</PickTitle><PickDescription>The house pair. Sharp and bright; Bodoni cut his types in Parma.</PickDescription></Pick><Pick value="press"><PickTitle>Press</PickTitle><PickDescription>Both made for reading news on screens. Plain, warm, unhurried.</PickDescription></Pick><Pick value="paris"><PickTitle>Paris</PickTitle><PickDescription>A narrow modern voice answered in the oldest italic here.</PickDescription></Pick><Pick value="salon"><PickTitle>Salon</PickTitle><PickDescription>A grotesque with a little ink trap, and a Garamond cut for display.</PickDescription></Pick></Picks><Picks variant="rubric" legend="Ink" defaultValue="vermilion"><Pick value="lamp"><PickTitle>Lamp black</PickTitle><PickDescription>Soot from an oil lamp, ground into varnish.</PickDescription></Pick><Pick value="vermilion"><PickTitle>Vermilion</PickTitle><PickDescription>The rubricator&rsquo;s red, ground from cinnabar.</PickDescription></Pick><Pick value="gall"><PickTitle>Iron gall</PickTitle><PickDescription>Brown-black, and it bites into the page for good.</PickDescription></Pick></Picks><Picks variant="watermark" legend="Paper" defaultValue="wove"><Pick value="laid"><PickTitle>Laid</PickTitle><PickDescription>Ribbed with the wires of the mould it was made on.</PickDescription></Pick><Pick value="wove"><PickTitle>Wove</PickTitle><PickDescription>Smooth as a page can be. Baskerville asked for it.</PickDescription></Pick><Pick value="cotton"><PickTitle>Cotton</PickTitle><PickDescription>Soft and heavy in the hand, and it outlasts us.</PickDescription></Pick></Picks><Picks variant="register" legend="Format" defaultValue="quarto"><Pick value="octavo"><PickTitle>Octavo</PickTitle><PickDescription>The sheet folded three times: sixteen pages, small in the hand.</PickDescription></Pick><Pick value="quarto"><PickTitle>Quarto</PickTitle><PickDescription>Folded twice into eight pages. About half of Shakespeare&rsquo;s plays first saw print this way.</PickDescription></Pick><Pick value="folio"><PickTitle>Folio</PickTitle><PickDescription>Folded once. Tall, grand and heavy on the lectern.</PickDescription></Pick></Picks></div>)}const line = "Plain, warm, unhurried."

Contract

  • Underneath: native radios, plus a hook that places pizzicato's dot and string and register's crosses.
  • Anatomy: <fieldset class="ot-picks" data-variant="pizzicato | rubric | watermark | register">, a legend, then <label><input type="radio">…any content…</label> per pick, usually <span class="ot-pick-title"> and <span class="ot-pick-description">. A plain-text title is written as <span aria-hidden data-initial><span class="ot-pick-initial" data-text><span>I</span></span><span class="ot-pick-rest" data-text><span>nitial</span></span></span> plus the whole name in .ot-sr. A name in a script without capitals (its first letter is the same upper and lower case) is marked data-caseless and not split: the initial holds a pilcrow and the rest holds the whole name. Pizzicato adds .ot-picks-string and .ot-picks-dot; register adds .ot-picks-origin and two .ot-picks-cross (data-corner="start | end").
  • For choices that carry their own content, such as a specimen or a swatch. Yours: the chosen title crosses into the italic (a cross-fade of an italic copy in the same cell, so nothing moves), and its description steps up from pencil to graphite.
  • Pizzicato (the default): one accent dot hangs in the margin beside the chosen title, level with its x-height. Pointing at another sketches a hairline ring where the dot would land; pressing tightens it. Choosing another slides the dot there (--ot-picks-y, moderato, breath) along a hairline string that runs the length of the list; the string is pulled aside as the dot travels, let go on arrival, rings in five shrinking half-swings and fades back to silence (data-plucked, a registered --ot-picks-d). The title turns italic as the dot lands. Script measures the picks (--ot-picks-top, --ot-picks-len, --ot-picks-y) on choice, resize and font load, and sets data-placed; until then the chosen pick's hover ring, filled in the accent, stands in for the dot, so nothing jumps at hydration. A first choice is plucked where it lands.
  • Rubric: the chosen title's initial is lifted out of the word and hung in the margin, two lines deep (title and the first description line), in the italic and the accent, the way a rubricator painted a section's one red letter. Every pick keeps the margin (--ot-space-7, inside the label so focus and the pointer include the capital), so nothing reflows: the capital grows from its place in the word into the margin (andante, exhale) while a ghost of the small letter narrows to nothing and the rest of the name closes up to the edge and turns italic. Pointing leans the initial italic in place. A pick without a description keeps that second line free. It mirrors in right-to-left. A cased name on a right-to-left page (a Latin name among Arabic) begins at the end away from the margin, so its initial has nowhere to hang: the name stays whole, in its own order (an isolated left-to-right run), and the pilcrow hangs in the margin instead. A pick given dir="ltr" is a left-to-right block and hangs its capital in its own margin. A name without capitals, as in Arabic, Hebrew, Devanagari or Han, has no initial to hang, and lifting its first letter out would break a joined word; there the rubricator's other mark, an accent pilcrow (mirrored right to left), grows into the margin instead, and the name stays whole.
  • Watermark: the chosen title lies behind the list, huge (--ot-fff in the expression italic) and faint (ink at 8%), set against the list's foot and end edge and cropped by them, the way a sheet shows its mould's mark held to the light and the poster's ghost numerals stand behind its words. Each title carries its own mark (.ot-pick-title::before, from data-text), so choosing another fades one mark down while the next comes up out of the paper (andante, exhale); nothing travels. The title itself crosses into the italic as pizzicato's does. Forced colours drop the mark. A title with rich content has no mark.
  • Register: the printer's registration crosses, as the posters mark their corners with a pair of + signs. Two accent crosses stand off the chosen pick's far corners, the top of its start side and the foot of its end side, by --ot-picks-out. Script measures them (--ot-picks-x0, -y0, -x1, -y1) from .ot-picks-origin on choice, resize and font load. Choosing another sends the pair there (moderato, breath), the far one two arpeggio steps behind, each turning a quarter the way the pick went (--ot-picks-turn); a cross turned a quarter is the same cross, so it only reads as turning while it moves. Pointing sketches the pair in pencil at that pick. Until it's measured, the chosen pick's own pair stands in, inked. Each pick keeps --ot-space-5 either side for the crosses.
  • States: rest, hover (ink), focus (accent outline around the label), chosen, disabled (pencil at 55%, no hover). Forced colours: the dot, the rubric capital and the register crosses use Highlight, the ring, string and pencil crosses CanvasText. Reduced motion: every tempo collapses, so the dot and capital arrive without travel.
  • Keyboard: native radio group (Tab into the chosen pick, arrow keys move the choice).
  • The specimen uses it for the pair and scheme pickers.

Props

Props of Picks
PropTypeDefaultWhat it does
variant"pizzicato" | "rubric" | "watermark" | "register""pizzicato"How the choice is marked. pizzicato: one accent dot in the margin; choosing another slides it along a hairline string that is plucked, rings and falls silent. rubric: the chosen title's initial hangs in the margin two lines deep, in the italic and the accent, and the rest of the name closes up beside it; a name without capitals keeps whole and an accent pilcrow hangs there instead. watermark: the chosen title lies behind the list, huge, faint and cropped at its foot, and choosing another fades one mark into the next. register: two printer's registration crosses stand off the chosen pick's far corners and travel to the next, turning a quarter as they go; pointing sketches the pair in pencil. Nothing around it reflows.
namestringShared by every radio so a form submits the choice. Generated if left out.
legendReactNodeThe small label over the list. Without one, give the group an aria-label.
value / defaultValuestringThe chosen pick's value.
onValueChange(value: string) => voidCalled with the new value when the choice changes.
Pick valuestringWhat this choice stands for.
Pick childrenReactNodeAnything: a PickTitle and a PickDescription, a swatch, a specimen. Plain text is taken as the title.
PickTitle childrenReactNodeThe pick's name. Plain text crosses into the italic when chosen, and it is the text rubric takes the initial from and watermark sets behind the list. A name in a script without capitals (Arabic, Hebrew, Devanagari, Han) isn't split; rubric hangs a pilcrow beside it. A name in the other direction from the page takes a dir attribute.
PickDescriptionspan propsA line under the title, in the pencil; graphite once chosen. Rubric's capital drops through its first line.
Pick labelClassNamestringClasses for the choice's label wrapper. className goes to the native radio.

Craft

Where its move comes from

Where its move comes from
ComponentReferenceMove
PicksThe score's pizzicato; the rubricated initialA plucked string carries the dot; or the chosen initial hangs in the margin (a pilcrow, for a script without capitals)
Picks, watermarkThe poster's ghost numerals; the papermaker's watermarkThe chosen name lies huge and faint behind the list
Picks, registerThe posters' + corner signs; the printer's registration marksTwo crosses mark the chosen pick's far corners

How it moves

How it moves
ComponentArticulationWhat moves
PicksPizzicatoA ring on hover; the dot slides to the choice along a string that is plucked and rings to silence
Picks, rubricRubricationThe initial leans on hover; chosen, it grows into the margin as a two-line accent capital and the name closes up in italic
Picks, watermarkHeld to the lightOne mark fades down and the next comes up out of the paper
Picks, registerRegisterPencil crosses on hover; chosen, the accent pair travels to the new corners, turning a quarter, the far one a beat behind