Link
One link: a hairline underline at rest, and pointing at it, focusing it or holding its card open draws a highlighter stroke through the whole word, on from the left and off to the right.
Report an issue with LinkExample
The work is led by Ada Lindqvist, and the reading list sits with the Halden archive (opens in a new tab).
The grid follows the Swiss school, the pairs follow a type specimen of 1923, and the pauses follow the score.
RestAda Lindqvist
Pointed atAda Lindqvist
FocusAda Lindqvist
PressedAda Lindqvist
ReadAda Lindqvist
QuietAda Lindqvist
ReferenceSwiss school
Reference, pointed atSwiss school
AddressWrite to us
Address, pointed atWrite to us
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/link.jsonUsage
import { Link } from "@/components/ui/link"export default function Example() {return (<div className="grid gap-10"><p className="ot-mp max-w-[36rem]">The work is led by <Link href="#">Ada Lindqvist</Link>, and the reading list sits with{" "}<Link href="https://example.com" external>the Halden archive</Link>.</p><p className="ot-p max-w-[36rem]">The grid follows the <Link href="#" variant="reference">Swiss school</Link>, the pairs follow a type{" "}<Link href="#" variant="reference">specimen</Link> of 1923, and the pauses follow the <Link href="#" variant="reference">score</Link>.</p><ul className="ot-p grid gap-2"><li><Link href="mailto:studio@example.com" variant="address">Write to the studio</Link></li><li><Link href="https://example.com/halden/" variant="address" external>Read the archive</Link></li></ul></div>)}Contract
- Underneath: native
<a>. Its CSS lives in base.css, so every item may use it..ot-prose ais the same link. - One link. At rest, a hairline under the words in the current colour, clear of the descenders. Pointing, focusing (
:focus-visible) or holding its card open (data-state="open", a hover card's trigger) draws the highlighter through the whole word, ascenders and descenders included, on from the left and off to the right (mirrored right to left), and the hairline gives way to it. The stroke runs 0.12em past each end, like a pen overshooting, while the words stay put. The letters turn--ot-on-markexactly where the stroke has reached (two layers clipped to the text), so they are never dark on dark in Nocturne. The hairline and the overshoot come back once the pen has passed. - Focus: the stroke, with the accent line under it at
--ot-strokein place of the outline box (forced colours keep the outline). Pressed (:active): the line snaps back under the stroke in ink, at--ot-stroke. Read (:visited): the line fades to pencil; browsers let:visitedchange colour only, which is why the line is the box's bottom border and not a painted layer. external(the component prop): opens in a new tab, with "(opens in a new tab)" for screen readers, and a ↗ that hangs just past the end of the words, off the line, on the last line however the link wraps; the link keeps room for it, so it can't be stranded at the start of a line. Pointing sends it a step the way it points.data-variant="quiet": the line in--ot-rule-strong, for a run of links that already reads as links (an index, a programme), so the run isn't a barcode.--ot-link-linesets the line's colour directly.data-variant="reference": after the book's reference marks. No line; a raised mark after the words in the printer's order (* † ‡ § ‖ ¶, then doubled, a CSS counter with@counter-style ot-notes), numbered down the page. The mark says there is more; pointing strokes the words and the mark together. The mark is generated content with empty alternative text, so screen readers read only the words. For sources and definitions in running text.data-variant="address": after the printed page, where a link is spelled out so a reader can go there. Pointing or focusing writes where it goes, small, pencil and in parentheses (no scheme, nowww., no trailing slash), after the words from where they end, clear of the ↗ on an external link. A wrapping.ot-link-addressedspan holds the link and its.ot-link-addresssibling, reserving the address's measure even at rest so revealing it moves nothing. When there is no room beside the words, the address steps under; long addresses wrap. Use it for a link on its own line (a list, a footer). The address isaria-hidden; it isn't drawn withasChild.- Docs rows pin states with
data-force:hover,focus,press,visited.
Props
| Prop | Type | Default | What it does |
|---|---|---|---|
asChild | boolean | false | Render the child element, such as your router's link, with the link's look. |
external | boolean | false | Opens in a new tab and adds the ↗ after the words, clear of the underline; pointing sends it a step the way it points. |
variant | "quiet" | "reference" | "address" | quiet sets the underline in rule rather than the text's colour, for a run of links that already reads as links (an index, a programme). reference drops the line for a raised reference mark after the words, numbered down the page in the printer's order (* † ‡ § ‖ ¶). address writes where the link goes, in parentheses after the words, when you point at or focus it; its measure is reserved at rest, and it steps under when the line is full. Use it for a link on its own line, and not with asChild. | |
href / … | native | A real anchor, so every native prop works. |
Craft
Where its move comes from
| Component | Reference | Move |
|---|---|---|
| Link | Weingart letter's highlighter | The highlighter passes through the word |
| Reference link | The book's reference marks (* † ‡ § ‖ ¶) | No line; a raised mark says there is more |
| Address link | The printed page's spelled-out address; 20(25) | Pointing writes where it goes, in parentheses, after the words |
How it moves
| Component | Articulation | What moves |
|---|---|---|
| Link | Pass-through | The highlighter passes through the word and the line gives way; an external link's ↗ steps the way it points |
| Address link | Written | Pointing writes the address in from where the words end; leaving, it's taken back the other way |