Link is mainly used as navigational element and usually appear within or directly following a paragraph or sentence.

also known as Anchor, <a>, Text Link, Hyperlink

Figma:

Responsive:

Adaptive:

A11y:

Props

Component props
Name
Type
Default
href
Required
string
-

The URL that the hyperlink points to.

accessibilityLabel
string
-

Supply a short, descriptive label for screen-readers to replace link texts that don't provide sufficient context about the link component behavior. Texts like "Click Here", or "Read More" can be confusing when a screen reader reads them out of context. In those cases, we must pass an alternative text to replace the link text. It populates aria-label. Screen readers read the accessibilityLabel prop, if present, instead of the link text. See the Accessibility guidelines for more information.

children
React.Node
-

Link is a wrapper around components (or children), most commonly text, so that they become hyperlinks. See the Text and Link variant to learn more.

dataTestId
string
-

Available for testing purposes, if needed. Consider better queries before using this prop.

display
"inline" | "inlineBlock" | "block"
"block"

Determines how Link is positioned relative to surrounding elements, such as Text. See the inline variant to learn more.

externalLinkIcon
"none"
| "default"
| {
    color: $ElementType<ElementConfig<typeof Icon>, "color">,
    size: $ElementType<ElementConfig<typeof Text>, "size">,
  }
"none"

When supplied, a "visit" icon is shown at the end of Link. See the externalLinkIcon and rel variant to learn more.

id
string
-

Unique id attribute of the anchor tag.

onBlur
({ event: SyntheticFocusEvent<HTMLAnchorElement> }) => void
-

Callback triggered when when the element loses focus.

onClick
({
  event: SyntheticMouseEvent<HTMLAnchorElement> | SyntheticKeyboardEvent<HTMLAnchorElement>,
  dangerouslyDisableOnNavigation: () => void,
}) => void
-

Callback fired when Link is clicked (pressed and released) with a mouse or keyboard. See GlobalEventsHandlerProvider to learn more about link navigation.

onFocus
({ event: SyntheticFocusEvent<HTMLAnchorElement> }) => void
-

Callback triggered when the element gains focus.

ref
React.Ref<"a">
-

Ref that is forwarded to the underlying anchor element.

rel
"none" | "nofollow"
"none"

Establishes the relationship of the linked URL. Use rel="nofollow" for offsite links to inform search engines to ignore and not follow them. See the externalLinkIcon and rel variant to learn more.

rounding
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | "circle" | "pill"
0

Sets a border radius for Link. Select a rounding option that aligns with its children.

tapStyle
"none" | "compress"
"none"

When compress is supplied, Link is visually compressed on click.

target
null | "self" | "blank"
"null"

Define the frame or window to open the anchor defined on href:

  • 'null' opens the anchor in the same window.
  • 'blank' opens the anchor in a new window.
  • 'self' opens an anchor in the same frame.

See the target variant to learn more.

underline
"auto" | "none" | "always" | "hover"
"auto"

When underline is supplied, we override the underline style internally managed by the component. See the underline variant to learn more.

Usage guidelines

When to use
  • Primarily for navigation, and usually within or directly accompanying a sentence. In particular cases, a Link is used to trigger actions assisting in a task completion in addition to navigation. However, these links should still serve as a support to a navigation purpose.
  • Directing users to another page or a different portion of the same page.
  • Jump to an element on the same page.
  • Highlighting URL destinations.
When not to use
  • Actions that will change data, change a state, or trigger a high-emphasis action. Use Button instead.
  • In Heading, as headings aren't easily recognizable as interactive elements. Headings can act as anchor elements on the page (accompanied by the "link" Icon), but if the heading needs to take users to a different page, add a subtitle next to the heading with an inline Link instead.

Best practices

Do

Display an underline on inline Links in the context of heavy text around them or in dense layouts such as Links on dashboards. The underline helps to determine its interactivity and reinforces accessibility standards.

Don't

Use a bold font weight to represent inline Links in the context of text around them. Bold font weight in the text context can be perceived as emphasis purposes, and it could fail to convey interactivity.

Do

Use bold font-weight in link elements such as lists, profile and board names, and any link element that an underline style isn't necessary to convey interactivity. For example, the user easily recognizes the bold element as a link since it is a typical treatment across our surfaces.

Don't

Display an underline on Links that aren't within a paragraph context, for example, lists or table links, as it could create cognitive load. Please note: If these elements are nested inside message components, consider displaying an underline, as it reinforces interactivity.

Do

Match Link to the text size and font-weight of the content they are accompanying for consistency and visual balance.

Don't

Apply multiple text styles on links paired with text, as it can create inconsistency it can make it hard to scan. See the Link and color variant for guidelines.

Do

Display the external icon ("visit" icon) when the link text needs support to convey an external domain or subsite, and when it helps Pinners scan and pick a navigation option. If the name of the link clearly lets a user know they are going to an external site, the icon is not needed.

Don't

Use other icons to represent an external Link. Instead, use the appropriate external icon.

Do

Add clarity to external links through explicit link text and predictable destinations instead of overusing external icons when the link is surrounded by text content. If not possible, limit to a maximum of two external icons per paragraph.

Don't

Overuse external icons, especially when they are part of text content.

Displaying multiple icons within the same text block can cause unnecessary visual load and negatively impact readability. Instead, add clarity to external links through explicit link text.

Do

Provide a meaningful descriptive label to the link that clearly indicates the link’s destination.

Don't

Use generic phrases like "click here" or "go to" on links. Review Writing guidelines for reference.

Accessibility

Avoid using Link to perform actions other than navigation or accessing external pages. Link should serve a navigation purpose.

Accessible content

Sometimes we don't have space to be more verbose and the Link content can't provide enough context. In those cases, use the accessibilityLabel prop. accessibilityLabel adds an aria-label attribute to the link, which assistive technologies like screen readers can access. Typically, the label text replaces the visible text on the Link for users who use assistive technology. While we don't recommend using "Learn more" or "See details" for Link text, it can be used as long as it is supplemented with a more descriptive accessibilityLabel, like "Learn more about personalization and data" or "See rate limit details for trial package".

Accessible content is critical if we consider that assistive technology also presents links in isolation from their contexts. For example, screen reader rotors list all the links present in a page. If all listed links are repetitions of the same generic phrases, the content is not accessible.

import { Checkbox, Flex, Label, Link, Text } from 'gestalt';

export default function Example() {
  return (
    <Flex alignItems="center" height="100%" justifyContent="center">
      <Flex
        alignItems="center"
        direction="row"
        gap={{ column: 4, row: 0 }}
        width="90%"
        wrap
      >
        <Flex gap={{ column: 0, row: 2 }}>
          <Checkbox checked id="1" onChange={() => {}} size="sm" />
          <Label htmlFor="1">
            <Text>
              Use sites you visit to improve which recommendations and ads you
              see on Pinterest.{' '}
              <Link
                accessibilityLabel="Learn more about personalization and data"
                display="inline"
                href="https://pinterest.com/_/_/help/article/personalization-and-data#info-ad"
              >
                Learn more
              </Link>
            </Text>
          </Label>
        </Flex>
        <Flex gap={{ column: 0, row: 2 }}>
          <Checkbox checked id="2" onChange={() => {}} size="sm" />
          <Label htmlFor="2">
            <Text>
              Share activity for ads performance reporting.{' '}
              <Link
                accessibilityLabel="Learn more about ads performance reporting"
                display="inline"
                href="https://www.pinterest.com/_/_/help/article/ads-performance-reporting"
              >
                Learn more
              </Link>
            </Text>
          </Label>
        </Flex>
        <Flex gap={{ column: 0, row: 2 }}>
          <Checkbox checked id="3" onChange={() => {}} size="sm" />
          <Label htmlFor="3">
            <Text>
              Use your activity to improve ads you see about Pinterest on other
              sites or apps you may visit.{' '}
              <Link
                accessibilityLabel="Learn more about third-party analytics"
                display="inline"
                href="https://www.pinterest.com/_/_/help/article/third-party-analytics-or-advertising-providers-pinterest-uses-or-allows"
              >
                Learn more
              </Link>
            </Text>
          </Label>
        </Flex>
      </Flex>
    </Flex>
  );
}

import { Flex, Link, Table, Text } from 'gestalt';

export default function Example() {
  return (
    <Flex alignItems="center" height="100%" justifyContent="center">
      <Table
        accessibilityLabel="See what's possible with access tiers"
        maxHeight={200}
      >
        <Table.Header sticky>
          <Table.Row>
            <Table.HeaderCell> </Table.HeaderCell>
            <Table.HeaderCell>
              <Text weight="bold">Trial</Text>
            </Table.HeaderCell>
            <Table.HeaderCell>
              <Text weight="bold">Standard</Text>
            </Table.HeaderCell>
          </Table.Row>
        </Table.Header>
        <Table.Body>
          <Table.Row>
            <Table.Cell>
              <Text weight="bold">Basic analytics</Text>
            </Table.Cell>
            <Table.Cell>
              <Text>Included</Text>
            </Table.Cell>
            <Table.Cell>
              <Text>Included</Text>
            </Table.Cell>
          </Table.Row>
          <Table.Row>
            <Table.Cell>
              <Text weight="bold">Rate limits</Text>
            </Table.Cell>
            <Table.Cell>
              <Flex direction="column" gap={{ column: 2, row: 0 }}>
                <Text size="100">1000/day</Text>
                <Text>
                  <Link
                    accessibilityLabel="See rate limit details for trial package"
                    href="https://developers.pinterest.com/docs/api/v5/#tag/Rate-limits"
                    underline="always"
                  >
                    See details
                  </Link>
                </Text>
              </Flex>
            </Table.Cell>
            <Table.Cell>
              <Flex direction="column" gap={{ column: 1, row: 0 }}>
                <Text size="100">Variable</Text>
                <Text>
                  <Link
                    accessibilityLabel="See rate limit details for standard package"
                    href="https://developers.pinterest.com/docs/api/v5/#tag/Rate-limits"
                    underline="always"
                  >
                    See details
                  </Link>
                </Text>
              </Flex>
            </Table.Cell>
          </Table.Row>
        </Table.Body>
      </Table>
    </Flex>
  );
}

Keyboard navigation

Give Link keyboard focus with the tab key (or shift + tab when tabbing backwards). Activate Link with the enter/return key.

When rendering an external link, add text for screen readers that this Link will go to a different destination. Users should be informed that they will be moving out of a domain and which domain they are moving to. This is particularly relevant for those with cognitive impairments or people relying on assistive technology.

These are cases where external links should open in a new tab, as it supports Pinners to better navigate our product without disrupting their flow experience:

  • When changing pages would make the user lose unsaved progress—for example, filling out a form or adding content.

  • When starting a process, which would stop if the user clicks away. For example, watching a video or completing a core task.

  • When Pinners are logged in and, clicking away would interrupt that session.

Sometimes opening links in a new tab can be challenging for users with difficulty perceiving visual content, users with cognitive disabilities, or people who magnify their screens. We don't recommend opening a link in a new tab when:

  • It is invasive and disruptive to the flow of the page.

  • Users have not been clearly informed about this behavior.

We recommend adding an external link to inline content. However, use a maximum of two external links per paragraph when possible, as adding more than two icons in the same block of text can clutter the design and create readability issues.

Also, consider adding external links to elements where the "visit" icon will support the user's comprehension, letting them know they are leaving Pinterest content and going to an external domain. For example, when using external links inside a footer element.

For external links where an external Gestalt Link doesn't apply, check out Button link role or IconButton link role.

Localization

Be sure to localize all text strings. Note that localization can lengthen text by 20 to 30 percent.

Link depends on DefaultLabelProvider for internal text strings. Localize the texts via DefaultLabelProvider. Learn more
import { Box, DefaultLabelProvider, Flex, Link, Text } from 'gestalt';

export default function Example() {
  return (
    <DefaultLabelProvider
      // $FlowExpectedError[incompatible-type] For demostration purposes
      labels={{
        Link: {
          accessibilityNewTabLabel: 'Öffnet eine neue Browser-Registerkarte.',
        },
      }}
    >
      <Flex
        alignItems="center"
        height="100%"
        justifyContent="center"
        width="100%"
      >
        <Box paddingX={8} paddingY={8}>
          <Text>
            <Link
              accessibilityLabel="Besuchen Sie das Business Center von Pinterest, um zu erfahren, wie Sie Ihr Geschäft ausbauen können."
              display="inlineBlock"
              externalLinkIcon="default"
              href="https://business.pinterest.com/advertise"
              target="blank"
            >
              Besuchen Sie das Business Center von Pinterest
            </Link>
          </Text>
        </Box>
      </Flex>
    </DefaultLabelProvider>
  );
}

Variants

Link depends on Text to inherit style attributes including weight, color, and size. Aim to match the text size and style of the content they are accompanying. Always use Link within Text to get the correct underline color.

import { Box, Flex, Link, Text } from 'gestalt';

export default function Example() {
  return (
    <Flex alignItems="center" height="100%" justifyContent="center">
      <Box color="infoBase" padding={4} rounding={3} width="50%">
        <Flex
          alignItems="center"
          direction="column"
          gap={{ column: 3, row: 0 }}
        >
          <Text color="inverse" size="600" weight="bold">
            Tips
          </Text>
          <Flex alignItems="center" gap={{ row: 1, column: 0 }}>
            <Text align="center" color="inverse" size="400" weight="bold">
              <Link display="inline" href="https://pinterest.com">
                Add a Pinterest widget
              </Link>{' '}
              and get inspired right from your phone&lsquo;s home screen.
            </Text>
          </Flex>
        </Flex>
      </Box>
    </Flex>
  );
}

Link uses the typography color tokens. Keep in mind colors should be used purposefully and consistently as they convey meaning in multiple ways. See below how to use colors on links.

  1. color="default"
    Default text color for links used across Pinterest UI.
  2. color="subtle"
    Intended for links placed within a subtle inline text (e.g. additional link on a sub-header).
  3. color="inverse"
    For links over a dark-colored background. Make sure it has a 4.5:1 contrast ratio between foreground and background.
  4. color="shopping"
    Used on links related to shopping products or surfaces when a color is needed to highlight a link. Please note: This color should only be used in a shopping context.
  5. Status: color="error", color="warning", color="success"
    Used purposefully, applies only on links within a status message. See status colors for reference.
  6. Documentation: color="link"
    Reserved color for links within documentation and internal subsites when a color is needed to convey interactivity. Please note: This color shouldn't be used on links across Pinterest customer-facing UI.

Underline

To follow Link design guidelines and best practices, inline and underline props must be used accordingly. In addition, using Links consistently will ensure a great usability experience.

We recommend showing the underline on the link, at least upon a hover behavior; it will sustain accessibility standards. Only hide the underline if the link element has a different hover behavior (e.g., a color background), and the user can still perceive the element as a link. In that case, it’s always a good idea to test this assumption with users. Reach out to Gestalt for assistance.

Don’t underline Text that isn’t a Link, as underline has a strong link affordance.

Link with display="inline" or display="inlineBlock" sets the underline style to "always" to follow design guidelines while display="block" sets the underline style to "hover". On hover, underline="always" removes the underline, while underline="hover" adds it.

However, Link's underline style can be overridden at any time using the underline prop.

underline="none" doesn't show any underline style. However, for cases where underline isn’t needed to convey interactivity or when the link element doesn’t function as a link visually, consider using TapArea or Button with role=link.

import { Flex, Link, Text } from 'gestalt';

export default function Example() {
  return (
    <Flex alignItems="center" height="100%" justifyContent="center">
      <Flex direction="row" width="90%" wrap>
        <Text inline>
          Find tips and best practices on the{' '}
          <Link display="inline" href="https://business.pinterest.com/">
            Pinterest Business Site{' '}
          </Link>
        </Text>
      </Flex>
    </Flex>
  );
}

Inline Link
import { Box, Flex, Link, Text } from 'gestalt';

export default function Example() {
  return (
    <Flex alignItems="center" height="100%" justifyContent="center">
      <Flex gap={{ row: 4, column: 0 }} width={300} wrap>
        {[
          'About',
          'Blog',
          'Business',
          'Careers',
          'Developers',
          'Removals',
          'Privacy',
          'Personalized ads',
          'Terms',
        ].map((item, idx) => (
          <Text key={idx} color="subtle" weight="bold">
            <Box paddingY={1}>
              <Link href="https://www.pinterest.com/">{item}</Link>
            </Box>
          </Text>
        ))}
      </Flex>
    </Flex>
  );
}

Standalone Link
import { Avatar, Box, Flex, Link, Text } from 'gestalt';

export default function Example() {
  return (
    <Flex
      alignItems="center"
      gap={2}
      height="100%"
      justifyContent="center"
      width="100%"
    >
      <Box aria-hidden>
        <Avatar
          accessibilityLabel="Shanice Romero"
          name="Shanice Romero"
          size="sm"
          src="https://i.ibb.co/7tGKGvb/shanice.jpg"
        />
      </Box>
      <Text>
        <Text inline weight="bold">
          <Link
            display="inline"
            href="https://www.pinterest.com"
            underline="hover"
          >
            {' '}
            Shanice Romero{' '}
          </Link>
        </Text>{' '}
        saved to
        <Text inline weight="bold">
          <Link
            display="inline"
            href="https://www.pinterest.com"
            underline="hover"
          >
            {' '}
            Capoeira{' '}
          </Link>
        </Text>
      </Text>
    </Flex>
  );
}

Inline Link with overridden underline
import { Flex, Link, Text } from 'gestalt';

export default function Example() {
  return (
    <Flex
      alignItems="center"
      gap={2}
      height="100%"
      justifyContent="center"
      width="100%"
    >
      <Text weight="bold">
        <Link
          display="inline"
          href="https://www.pinterest.com"
          underline="none"
        >
          I&lsquo;m a link with no underline
        </Link>
      </Text>
    </Flex>
  );
}

Link with hidden underline

Inline

By default, Link is a block-level element. When Link needs to be displayed inline with the surrounding elements, you can use the display prop set to "inline" or "inlineBlock". As shown below, the primary difference is how the words within the Link wrap when width is restricted. "inline" will wrap by word, whereas "inlineBlock" will wrap the entire block of words.

Note that when display="inline" is used, tapStyle="compress" is not respected.

Which should you choose? If you need inline Links, you most likely want display="inline". Only choose display="inlineBlock" if you need the compress animation on click/tap.

Play around with the container width on the examples below and note how each responds to wrapping.

import { useState } from 'react';
import { Box, Flex, Link, NumberField, Text } from 'gestalt';

function TextExample({ linkDisplay, maxWidth }) {
  return (
    <Box borderStyle="sm" maxWidth={maxWidth} padding={2} rounding={2}>
      <Text>
        To stop seeing content from an advertiser,{' '}
        <Text inline weight="bold">
          <Link display={linkDisplay} href="/">
            learn how to block accounts.
          </Link>
        </Text>{' '}
        Note that you can also unblock accounts.
      </Text>
    </Box>
  );
}

export default function Example() {
  const [containerWidth, setContainerWidth] = useState(250);

  return (
    <Box height="100%" padding={2} width="100%">
      <Flex
        alignItems="center"
        direction="column"
        gap={6}
        height="100%"
        width="100%"
      >
        <NumberField
          id="inlineExample"
          label="Container width (px)"
          onChange={({ value }) => {
            setContainerWidth(value ?? 0);
          }}
          value={containerWidth}
        />

        <Flex gap={6}>
          <Flex direction="column" gap={2}>
            <Text>Inline</Text>
            <TextExample linkDisplay="inline" maxWidth={containerWidth} />
          </Flex>

          <Flex direction="column" gap={2}>
            <Text>Inline Block</Text>
            <TextExample linkDisplay="inlineBlock" maxWidth={containerWidth} />
          </Flex>
        </Flex>
      </Flex>
    </Box>
  );
}

Target

target is optional and defines the frame or window to open the anchor defined on href:

  • "null" opens the anchor in the same window.
  • "blank" opens the anchor in a new window.
  • "self" opens an anchor in the same frame.
import { Flex, Link, Text } from 'gestalt';

export default function Example() {
  return (
    <Flex alignItems="center" height="100%" justifyContent="center">
      <Text inline>
        Find tips and best practices on the{' '}
        <Link display="inline" href="https://business.pinterest.com/">
          Pinterest Business Site
        </Link>
      </Text>
    </Flex>
  );
}

externalLinkIcon and rel

An external link, also called an outbound link, is a link from Pinterest to a different website. External links require specific SEO, visual, and accessibility treatments.

rel is optional. Use "nofollow" for external links to specify to web crawlers not follow the link. Don't use "nofollow" with urls redirecting to any Pinterest domain or subsite.

externalLinkIcon is optional. externalLinkIcon displays a "visit" icon at the end of external Links to visually communicate an outbound link destination to the user. Follow Link's Best practices to properly use the "visit" icon on external Links.

As the "visit" icon is a visual/graphic representation, it's hidden to assistive technologies to avoid duplication of information. Instead, follow accessibility best practices for external links as detailed in the Accessibility section.

The "visit" icon should also match Text's size and color. externalLinkIcon="default" automatically sets the "visit" icon style to match Text's default properties: size="300" and color="default" as shown in the first example. However, for different Text treatments, externalLinkIcon can be used to match custom Text properties as shown in the second example.

import { Flex, Link, Text } from 'gestalt';

export default function Example() {
  return (
    <Flex alignItems="center" height="100%" justifyContent="center">
      <Flex gap={{ row: 4, column: 0 }} width={300} wrap>
        <Text inline>
          To receive push notifications instead of texts,{' '}
          <Link
            display="inline"
            externalLinkIcon="default"
            href="https://authy.com/download/"
            rel="nofollow"
            target="blank"
          >
            download the Authy app
          </Link>
        </Text>
      </Flex>
    </Flex>
  );
}

import { Flex, Link, Text } from 'gestalt';

export default function Example() {
  return (
    <Flex alignItems="center" height="100%" justifyContent="center">
      <Flex direction="column" gap={{ column: 4, row: 0 }} width={300}>
        <Text inline size="100">
          Visit{' '}
          <Link
            display="inline"
            externalLinkIcon={{ size: '100', color: 'dark' }}
            href="https://authy.com/download/"
            rel="nofollow"
            target="blank"
          >
            MyBusiness.com
          </Link>{' '}
          for shipping details
        </Text>
        <Text color="success" inline size="400">
          <Link
            display="inline"
            externalLinkIcon={{ size: '400', color: 'success' }}
            href="https://authy.com/download/"
            rel="nofollow"
            target="blank"
          >
            MyBusiness.com
          </Link>{' '}
          was successfully claimed
        </Text>
      </Flex>
    </Flex>
  );
}

External handlers

Link consumes external handlers from GlobalEventsHandlerProvider.

Handlers:

See GlobalEventsHandlerProvider for more information.

Writing

Do
  • Link should be 3 words or less: long enough to be understood by users but short enough to prevent text wrapping
  • Use meaningful words that makes sense even out of context. Provide a meaningful descriptive label to the link that clearly indicates the link’s destination
  • Use the name of the page rather than the URL. For example, "Visit Pinterest.com" rather than "Visit www.pinterest.com"
Don't
  • Use text like "Click here" or "See more". Instead, write a meaningful descriptive label that clearly indicates the link’s destination.
  • Use all-caps

Component quality checklist

Component quality checklist
Quality item
Status
Status description
Figma Library
Component is not currently available in Figma.
Responsive Web
Ready
Component responds to changing viewport sizes in web and mobile web.

Internal documentation

Text
Text provides Link with style: size, color, and font.

Button
Button allows users to take actions, and make choices using text labels to express what action will occur when the user interacts with it.

Button, IconButton, TapArea
These components support link functionality themselves by setting role="link". Don't use Link to add link functionality to elements other than text.