Text link

A link that is part of a sentence, so the reader can follow a source or a related page without leaving the line.

Atom · stable · v1.0.0 · owner: Site system lead · contract 19 of 20 points (open: figma)

Do and don't

Do: A link that names its destination

Rendered by text-link.ts

Open example: Text link · Do: A link that names its destination Use the full-page example to follow page links.

Read alone in a list of links, it still says where it goes.

Do: A data file in a caption

Rendered by text-link.ts

Open example: Text link · Do: A data file in a caption Use the full-page example to follow page links.

The claim is one click from its evidence.

Don't: 'Click here'

Rendered by text-link.ts

Open example: Text link · Don't: 'Click here' Use the full-page example to follow page links.

Out of context it says nothing.

Don't: A next step as a text link

Rendered by text-link.ts

Open example: Text link · Don't: A next step as a text link Use the full-page example to follow page links.

The main action deserves a button, not a link lost in a sentence.

Rules

RuleWhyCheck
Link text says where it goes.Screen readers and skimming readers see links without the sentence around them.Automated: glossary checker: forbidden link texts (apps/showcase/site/loom/content)
Links in text are always underlined.Colour alone does not mark a link for people who cannot tell the colours apart.Automated: brand gate (core/base.css: a { text-decoration })

API

PropTypeRequiredDefaultWhat it does
labelstringYesWords that say where the link goes.
hrefstringYesThe destination.
externalbooleanNofalseOpens a source on another site; adds rel=noopener.

Contract details

The full contract: identity, anatomy, variants, states, tokens, layout, motion, accessibility, content, tests

Identity

AspectValue
Idtext-link
LayerAtoms
Categorynavigation
OwnerSite system lead
Statusstable
Version1.0.0
Sourceapps/showcase/site/system/atoms/text-link.ts (private repository; the contract and the render function are this one module)
VersionDateChange
1.0.02026-10-26Links inside sentences: underlined in the text colour, thicker on hover.

Use when

  • A word or phrase in running text points to another page or a source. Why: The link reads as part of the argument and keeps the sentence intact.
  • A caption names its data file. Why: The reader can check the data behind the claim in one click.

Do not use when

  • The link is the next step of the page. Why: Next steps are arrow links or buttons, which stand on their own line.
  • The link text would be 'here' or 'this'. Why: Link text must say where it goes when read alone, as screen readers list links out of context.

Anatomy

PartWhat it is
roota, underlined with --rule-hair at --space-2 offset, in the current text colour.

Made of: tokens:colour, tokens:type.

Used in: caption, breadcrumbs, job-map, atomic-guide, contents, footer, library-grid, product-screen, task-footer, task-header, persona-strip.

Variants

VariantWhenWhy
in textInside a paragraph or caption.It inherits the paragraph's colour so it never shouts.

States

StateRendered or not applicable
defaultUnderlined at 45% of the text colour
hoverThe underline turns the full text colour.
focus-visibleThe 3 px --focus ring.
activeNot applicable: Links show no separate pressed state; navigation is instant.
disabledNot applicable: A link that cannot be followed is not rendered as a link.
loadingNot applicable: Static link.
emptyNot applicable: The builder rejects an empty label.
errorNot applicable: Broken links fail the build's link test instead (tests/site/pages.spec.ts).
currentNot applicable: Text links do not mark the current page; the navigation does.
visitedSame colour as unvisited, on purpose: the text colour carries the meaning, and the underline marks the link.
expandedNot applicable: Does not open anything.

Tokens

PartToken
root.colorinherit (the paragraph's text role)
root.text-decoration-color45% of currentColor; currentColor on hover
root.text-decoration-thickness--rule-hair
root.text-underline-offset--space-2
--text-link-font-weight-weight-strongvar(--weight-strong)

Layout

AspectValue
breakpointsRequired review at 390, 768, 1024 and 1440 px; execution is not implied by this declaration; wraps with the sentence.
wrappingLong URLs break anywhere inside prose so they never widen the page.
textExpansionWraps with the text; no fixed width.

Spacing and rhythm

AspectValue
internalNone.
externalPart of the line.
rhythmNot a section element.

Motion

AspectValue
NoneA link in text only changes its underline colour; nothing moves.

Runtime and reuse

  1. Render-only element; mount any registered child enhancements separately. Preserve required Site CSS, fonts, responsive and locale rules from nativeElement.

Accessibility passport

AspectValue
rolelink
nameThe visible words
keyboardEnter follows the link.
focusIn reading order with the --focus ring.
screenReaderReads 'link' and the words; external links say where they go in the words.
contrastThe text colour's contrast (4.5:1 or better); the underline marks it as a link without colour alone.
targetInline links are exempt from the 24 px target rule (WCAG 2.5.8 inline exception).

Content

SlotLengthVoice
label8 wordsSay where it goes: 'the cost of drift', not 'here'

Good: “on the cost of drift” · “rubric.json”

Bad: “click here” · “this page”

Japanese: Text comes from the page content; Japanese strings are reviewed per page (apps/showcase/site/loom/locales). Awaiting native review, as the banner on every Japanese page says.

Icons and illustrations

None: this element uses no icon or illustration of its own.

Decisions and exceptions

Usage

2 uses across the built pages (measured by npm run site:system).

Tests

AspectValue
unittests/unit/site-system.test.ts: renders every do and don't example through the registry and checks the classes it owns
visualNot yet: there are no screenshot baselines; the Library page is checked for sideways scroll at 1440 px by tests/site/system.spec.ts
a11ytests/site/system.spec.ts: axe (0 serious or critical) on the element's Library page in light and dark
parityscripts/site/system/check.ts: Library examples are rendered by the same render function the site imports

Figma

not-yet: The Loom Site Figma library is the last stage of the plan; this element is not mapped yet.

Open in Storybook

Start with a conversation about your system.

We read your system, show you what we found, and agree with your team what to fix first.