Docs
Link

Link

Router-agnostic textual link. By default it renders a native <a>; for SPA navigation, pass as with the consumer framework's Link (Next.js, react-router, Remix, etc.). External URLs (http(s), mailto:, tel:, sms:) are detected automatically and get target="_blank" + rel="noopener noreferrer" (merged with the consumer's rel), ignoring the consumer's as — absolute URLs break when run through a router's basename, so external links are always forced to a native <a> regardless of what as was passed.

When to use

✅ Use when…🚫 Avoid when…
  • For external content (absolute href) — security and new tab come ready-made.
  • For navigation inside the SPA via as={FrameworkLink} (Next.js, react-router, Remix).
  • When you need a link that looks like a button, use Link.Button.
  • For actions that do not navigate. Use Button — a link communicates "go somewhere else", a button communicates "do something here".
  • As a submit button in forms. Use Button type="submit".

Regular Link (native <a>)

Pass href to create a basic link — renders a native <a>.

loading

For external URLs, target="_blank" and rel="noopener noreferrer" are added automatically.

rel is merged, not overwritten

noopener and noreferrer are non-negotiable on external links and always come first, but the consumer's rel is preserved — useful for SEO hygiene on external source citation links (nofollow), user-generated content (ugc), paid links (sponsored) or identity (me). Tokens are deduplicated and normalized to lowercase.

<Link href="https://example.com" rel="nofollow" text="Article citation" />
// renders: rel="noopener noreferrer nofollow"

target, on the other hand, remains forced on external links — new tab is the DS contract. On internal href the consumer's rel is passed through as-is, with no injection.

Content: text or children

Pass the label as text (a string) or as children (JSX) — children takes precedence. Using children makes Link the sanctioned replacement for a hand-rolled <a> (or a raw factory anchor): you render arbitrary content while keeping the DS link's external-link security and its guaranteed AA contrast floor. Reach for Link — not Text as="a" — for anything that navigates; Text as="a" is a plain anchor and gets none of that.

loading

// string
<Link href="/docs" text="Docs" />
 
// JSX children — takes precedence over text
<Link href="/docs"><strong>Docs</strong> — read the guide</Link>

Link is a content/typography element — it does not lay its own children out with flex. When a link's content needs layout (an icon beside a wordmark), nest a layout container as the child; the anchor still keeps the link security + contrast:

<Link href="/" contrast="main" textDecoration="none">
  <Flex as="span" flexDirection="row" alignItems="center" gap="xs">
    <Icon icon={logo} />
    <Text as="span">Home</Text>
  </Flex>
</Link>

Integrating with a routing framework

For SPA navigation, pass the framework's Link via the as prop. Extra props (to, href, prefetch, etc.) are forwarded via spread — the DS does not dictate the router's contract.

Next.js

import NextLink from 'next/link';
import { Link } from '@apollion-dsi/core/elements/link';
 
<Link as={NextLink} href="/perfil" text="My profile" />;

react-router-dom

import { Link as RouterLink } from 'react-router-dom';
import { Link } from '@apollion-dsi/core/elements/link';
 
<Link as={RouterLink} to="/perfil" text="My profile" />;

Remix

import { Link as RemixLink } from '@remix-run/react';
import { Link } from '@apollion-dsi/core/elements/link';
 
<Link as={RemixLink} to="/perfil" text="My profile" />;

Link as a Button

Use Link.Button for a link that looks like a Button — it inherits variants, colors and sizes. Same polymorphic pattern via as.

<Link.Button
  href="https://pt-br.react.dev/blog/2023/03/16/introducing-react-dev"
  text="React Link as a Button"
  variant="contained"
  color="warning"
/>;
 
// With a framework:
import NextLink from 'next/link';
<Link.Button as={NextLink} href="/login" text="Sign in" variant="contained" />;

Linked variant as inline navigation

variant="linked" is the chrome-less Link.Button: no chip padding, no forced bold — it shares the text's left edge, so a breadcrumb or quiet nav can use it without switching to a plain Link.

<Link.Button href="/" text="Home" variant="linked" size="small" />

Underline and accessibility

The link underline follows the rule of never distinguishing a link by color alone (WCAG 1.4.1). There are two modes, and a context engine in Text.

Default: permanent underline

A standalone Link comes underlined — the safe mode for inline links in running text.

Quiet link (textDecoration="none")

In chrome/navigation (navbar, footer) the permanent underline feels heavy. Pass textDecoration="none" to remove it at rest; :hover and :focus-visible restore the underline, keeping the accessibility affordance without the link looking like a button.

<Link href="/docs" textDecoration="none" text="Docs" />
// no underline at rest; underline on mouse hover / keyboard focus

Link inside prose (context engine)

Any Link inside a <Text> is underlined by the container, regardless of the link's own textDecoration — the one who knows it is prose is the Text, so it is the one asserting the rule. Link.Button is left out and keeps its button appearance.

Read our privacy policy and the terms of use before proceeding.

Sign in
<Text variant="p">
  Read our <Link href="/privacidade" text="privacy policy" /> and the{' '}
  <Link href="/termos" textDecoration="none" text="terms of use" /> before proceeding.{' '}
  <Link.Button href="/entrar" text="Sign in" variant="contained" />
</Text>
// both text links get underlined (even the textDecoration="none" one);
// the Link.Button does not receive a text underline

Color on surface bands (contrast)

On a band with a brand background (header/footer on main), pass contrast="main": the link color is already that surface's on-color, without being remapped against the page background — which would break legibility on the band.

<Paper bgColor="main" padding="xl" gap="large" deep={0}>
  <Link href="/privacidade" contrast="main" text="Privacy" />
  <Link href="/termos" contrast="main" text="Terms" />
</Paper>

Properties

No public props documented for Link.

Besides the props above, every component accepts the layout props (spacing, color, flex/grid, sizing, border) — not repeated here.

See also

  • Storybook story: Components / Link
  • Base appearance: Button, Text