beta

Link

A link allows a user to navigate to another page or resource within a web page or application.

installyarn add react-aria-components
version1.0.0-beta.1
usageimport {Link} from 'react-aria-components'

Example#


import {Link} from 'react-aria-components';

<Link href="https://www.imdb.com/title/tt6348138/" target="_blank">
  The missing link
</Link>
import {Link} from 'react-aria-components';

<Link
  href="https://www.imdb.com/title/tt6348138/"
  target="_blank"
>
  The missing link
</Link>
import {Link} from 'react-aria-components';

<Link
  href="https://www.imdb.com/title/tt6348138/"
  target="_blank"
>
  The missing link
</Link>
Show CSS
.react-aria-Link {
  --focus-ring-color: slateblue;
  --text-color: var(--spectrum-global-color-blue-600);
  --text-color-pressed: var(--spectrum-global-color-blue-700);
  --text-color-disabled: gray;

  color: var(--text-color);
  font-size: 18px;
  transition: all 200ms;
  text-decoration: underline;
  cursor: pointer;
  outline: none;
  position: relative;

  &[data-hovered] {
    text-decoration-style: wavy;
  }

  &[data-pressed] {
    color: var(--text-color-pressed);
  }

  &[data-disabled] {
    cursor: default;
    color: var(--text-color-disabled);
  }

  &[data-focus-visible]:after {
    content: '';
    position: absolute;
    inset: -3px -6px;
    border-radius: 6px;
    border: 2px solid var(--focus-ring-color);
  }
}

@media (forced-colors: active) {
  .react-aria-Link {
    --focus-ring-color: Highlight;
    --text-color: LinkText;
    --text-color-pressed: LinkText;
    --text-color-disabled: GrayText;
  }
}
.react-aria-Link {
  --focus-ring-color: slateblue;
  --text-color: var(--spectrum-global-color-blue-600);
  --text-color-pressed: var(--spectrum-global-color-blue-700);
  --text-color-disabled: gray;

  color: var(--text-color);
  font-size: 18px;
  transition: all 200ms;
  text-decoration: underline;
  cursor: pointer;
  outline: none;
  position: relative;

  &[data-hovered] {
    text-decoration-style: wavy;
  }

  &[data-pressed] {
    color: var(--text-color-pressed);
  }

  &[data-disabled] {
    cursor: default;
    color: var(--text-color-disabled);
  }

  &[data-focus-visible]:after {
    content: '';
    position: absolute;
    inset: -3px -6px;
    border-radius: 6px;
    border: 2px solid var(--focus-ring-color);
  }
}

@media (forced-colors: active) {
  .react-aria-Link {
    --focus-ring-color: Highlight;
    --text-color: LinkText;
    --text-color-pressed: LinkText;
    --text-color-disabled: GrayText;
  }
}
.react-aria-Link {
  --focus-ring-color: slateblue;
  --text-color: var(--spectrum-global-color-blue-600);
  --text-color-pressed: var(--spectrum-global-color-blue-700);
  --text-color-disabled: gray;

  color: var(--text-color);
  font-size: 18px;
  transition: all 200ms;
  text-decoration: underline;
  cursor: pointer;
  outline: none;
  position: relative;

  &[data-hovered] {
    text-decoration-style: wavy;
  }

  &[data-pressed] {
    color: var(--text-color-pressed);
  }

  &[data-disabled] {
    cursor: default;
    color: var(--text-color-disabled);
  }

  &[data-focus-visible]:after {
    content: '';
    position: absolute;
    inset: -3px -6px;
    border-radius: 6px;
    border: 2px solid var(--focus-ring-color);
  }
}

@media (forced-colors: active) {
  .react-aria-Link {
    --focus-ring-color: Highlight;
    --text-color: LinkText;
    --text-color-pressed: LinkText;
    --text-color-disabled: GrayText;
  }
}

Features#


Links can be created in HTML with the <a> element with an href attribute. However, if the link does not have an href, and is handled client side with JavaScript instead, it will not be exposed to assistive technology properly. Link helps achieve accessible links with either native HTML elements or custom element types.

  • Flexible – Support for HTML navigation links, JavaScript handled links, and client side routing. Disabled links are also supported.
  • Accessible – Implemented as a custom ARIA link when handled via JavaScript, and otherwise as a native HTML link.
  • Styleable – Hover, press, and keyboard focus states are provided for easy styling. These states only apply when interacting with an appropriate input device, unlike CSS pseudo classes.

Anatomy#


A link consists of a pressable area usually containing a textual label or an icon that users can click or tap to navigate to another page or resource. In addition, keyboard users may activate links using the Enter key.

If a visual label is not provided (e.g. an icon or image only link), then an aria-label or aria-labelledby prop must be passed to identify the link to assistive technology.

Content#


Links accept content as children. If the link has an href prop, it will be rendered as an <a> element.

<Link href="https://adobe.com" target="_blank">Adobe.com</Link>
<Link href="https://adobe.com" target="_blank">
  Adobe.com
</Link>
<Link
  href="https://adobe.com"
  target="_blank"
>
  Adobe.com
</Link>

When a <Link> does not have an href prop, it is rendered as a <span role="link"> instead of an <a>. Events will need to be handled in JavaScript with the onPress prop.

Note: this will not behave like a native link. Browser features like context menus and open in new tab will not apply.

<Link onPress={() => alert('Pressed link')}>Adobe</Link>
<Link onPress={() => alert('Pressed link')}>Adobe</Link>
<Link
  onPress={() =>
    alert(
      'Pressed link'
    )}
>
  Adobe
</Link>

Events#


Link supports user interactions via mouse, keyboard, and touch. You can handle all of these via the onPress prop. This is similar to the standard onClick event, but normalized to support all interaction methods equally. In addition, the onPressStart, onPressEnd, and onPressChange events are fired as the user interacts with the link.

Each of these handlers receives a PressEvent, which exposes information about the target and the type of event that triggered the interaction. See usePress for more details.

function Example() {
  let [pointerType, setPointerType] = React.useState('');

  return (
    <>
      <Link
        onPressStart={(e) => setPointerType(e.pointerType)}
        onPressEnd={() => setPointerType('')}
      >
        Press me
      </Link>
      <p>
        {pointerType
          ? `You are pressing the link with a ${pointerType}!`
          : 'Ready to be pressed.'}
      </p>
    </>
  );
}
function Example() {
  let [pointerType, setPointerType] = React.useState('');

  return (
    <>
      <Link
        onPressStart={(e) => setPointerType(e.pointerType)}
        onPressEnd={() => setPointerType('')}
      >
        Press me
      </Link>
      <p>
        {pointerType
          ? `You are pressing the link with a ${pointerType}!`
          : 'Ready to be pressed.'}
      </p>
    </>
  );
}
function Example() {
  let [
    pointerType,
    setPointerType
  ] = React.useState('');

  return (
    <>
      <Link
        onPressStart={(e) =>
          setPointerType(
            e.pointerType
          )}
        onPressEnd={() =>
          setPointerType(
            ''
          )}
      >
        Press me
      </Link>
      <p>
        {pointerType
          ? `You are pressing the link with a ${pointerType}!`
          : 'Ready to be pressed.'}
      </p>
    </>
  );
}

Client side routing#

The <Link> component works with frameworks and client side routers like Next.js and React Router. As with other React Aria components that support links, this works via the RouterProvider component at the root of your app. See the client side routing guide to learn how to set this up.

Disabled#


A link can be disabled by passing the isDisabled property. This will work with both native link elements as well as client handled links. Native navigation will be disabled, and the onPress event will not be fired. The link will be exposed as disabled to assistive technology with ARIA.

<Link isDisabled href="https://adobe.com" target="_blank">Disabled link</Link>
<Link isDisabled href="https://adobe.com" target="_blank">
  Disabled link
</Link>
<Link
  isDisabled
  href="https://adobe.com"
  target="_blank"
>
  Disabled link
</Link>

Props#


NameTypeDescription
isDisabledbooleanWhether the link is disabled.
autoFocusbooleanWhether the element should receive focus on render.
hrefstringA URL to link to. See MDN.
targetHTMLAttributeAnchorTargetThe target window for the link. See MDN.
relstringThe relationship between the linked resource and the current page. See MDN.
downloadbooleanstringCauses the browser to download the linked URL. A string may be provided to suggest a file name. See MDN.
pingstringA space-separated list of URLs to ping when the link is followed. See MDN.
referrerPolicyHTMLAttributeReferrerPolicyHow much of the referrer to send when following the link. See MDN.
childrenReactNode( (values: LinkRenderProps )) => ReactNodeThe children of the component. A function may be provided to alter the children based on component state.
classNamestring( (values: LinkRenderProps )) => stringThe CSS className for the element. A function may be provided to compute the class based on component state.
styleCSSProperties( (values: LinkRenderProps )) => CSSPropertiesThe inline style for the element. A function may be provided to compute the style based on component state.
Events
NameTypeDescription
onPress( (e: PressEvent )) => voidHandler that is called when the press is released over the target.
onPressStart( (e: PressEvent )) => voidHandler that is called when a press interaction starts.
onPressEnd( (e: PressEvent )) => void

Handler that is called when a press interaction ends, either over the target or when the pointer leaves the target.

onPressChange( (isPressed: boolean )) => voidHandler that is called when the press state changes.
onPressUp( (e: PressEvent )) => void

Handler that is called when a press is released over the target, regardless of whether it started on the target or not.

onFocus( (e: FocusEvent<Target> )) => voidHandler that is called when the element receives focus.
onBlur( (e: FocusEvent<Target> )) => voidHandler that is called when the element loses focus.
onFocusChange( (isFocused: boolean )) => voidHandler that is called when the element's focus status changes.
onKeyDown( (e: KeyboardEvent )) => voidHandler that is called when a key is pressed.
onKeyUp( (e: KeyboardEvent )) => voidHandler that is called when a key is released.
Layout
NameTypeDescription
slotstringnull

A slot name for the component. Slots allow the component to receive props from a parent component. An explicit null value indicates that the local props completely override all props received from a parent.

Accessibility
NameTypeDescription
aria-labelstringDefines a string value that labels the current element.
aria-labelledbystringIdentifies the element (or elements) that labels the current element.
aria-describedbystringIdentifies the element (or elements) that describes the object.
aria-detailsstringIdentifies the element (or elements) that provide a detailed, extended description for the object.

Styling#


React Aria components can be styled in many ways, including using CSS classes, inline styles, utility classes (e.g. Tailwind), CSS-in-JS (e.g. Styled Components), etc. By default, all components include a builtin className attribute which can be targeted using CSS selectors. These follow the react-aria-ComponentName naming convention.

.react-aria-Link {
  /* ... */
}
.react-aria-Link {
  /* ... */
}
.react-aria-Link {
  /* ... */
}

A custom className can also be specified on any component. This overrides the default className provided by React Aria with your own.

<Link className="my-link">
  {/* ... */}
</Link>
<Link className="my-link">
  {/* ... */}
</Link>
<Link className="my-link">
  {/* ... */}
</Link>

In addition, some components support multiple UI states (e.g. focused, placeholder, readonly, etc.). React Aria components expose states using data attributes, which you can target in CSS selectors. For example:

.react-aria-Link[data-pressed] {
  /* ... */
}
.react-aria-Link[data-pressed] {
  /* ... */
}
.react-aria-Link[data-pressed] {
  /* ... */
}

The className and style props also accept functions which receive states for styling. This lets you dynamically determine the classes or styles to apply, which is useful when using utility CSS libraries like Tailwind.

<Link
  className={({ isPressed }) => isPressed ? 'bg-gray-700' : 'bg-gray-600'}
/>
<Link
  className={({ isPressed }) =>
    isPressed ? 'bg-gray-700' : 'bg-gray-600'}
/>
<Link
  className={(
    { isPressed }
  ) =>
    isPressed
      ? 'bg-gray-700'
      : 'bg-gray-600'}
/>

Render props may also be used as children to alter what elements are rendered based on the current state. For example, you could render an extra element when the link is in a pressed state.

<Link>
  {({isPressed}) => (
    <>
      {isPressed && <PressHighlight />}
      Press me
    </>
  )}
</Link>
<Link>
  {({isPressed}) => (
    <>
      {isPressed && <PressHighlight />}
      Press me
    </>
  )}
</Link>
<Link>
  {({ isPressed }) => (
    <>
      {isPressed && (
        <PressHighlight />
      )}
      Press me
    </>
  )}
</Link>

The states, selectors, and render props for Link are documented below.

NameCSS SelectorDescription
isCurrent[data-current]Whether the link is the current item within a list.
isHovered[data-hovered]Whether the link is currently hovered with a mouse.
isPressed[data-pressed]Whether the link is currently in a pressed state.
isFocused[data-focused]Whether the link is focused, either via a mouse or keyboard.
isFocusVisible[data-focus-visible]Whether the link is keyboard focused.
isDisabled[data-disabled]Whether the link is disabled.

Advanced customization#


Contexts#

All React Aria Components export a corresponding context that can be used to send props to them from a parent element. This enables you to build your own compositional APIs similar to those found in React Aria Components itself. You can send any prop or ref via context that you could pass to the corresponding component. The local props and ref on the component are merged with the ones passed via context, with the local props taking precedence (following the rules documented in mergeProps).

ComponentContextPropsRef
LinkLinkContextLinkPropsHTMLAnchorElement

This example shows a Router component that accepts Link elements as children and keeps track of which one was last clicked.

import type {PressEvent} from 'react-aria-components';
import {LinkContext} from 'react-aria-components';

function Router({children}) {
  let [clicked, setClicked] = React.useState(null);
  let onPress = (e: PressEvent) => {
    setClicked(e.target.textContent);
  };

  return (
    <LinkContext.Provider value={{onPress}}>      {children}
      {clicked && `You clicked ${clicked}`}
    </LinkContext.Provider>
  );
}
import type {PressEvent} from 'react-aria-components';
import {LinkContext} from 'react-aria-components';

function Router({children}) {
  let [clicked, setClicked] = React.useState(null);
  let onPress = (e: PressEvent) => {
    setClicked(e.target.textContent);
  };

  return (
    <LinkContext.Provider value={{onPress}}>      {children}
      {clicked && `You clicked ${clicked}`}
    </LinkContext.Provider>
  );
}
import type {PressEvent} from 'react-aria-components';
import {LinkContext} from 'react-aria-components';

function Router(
  { children }
) {
  let [
    clicked,
    setClicked
  ] = React.useState(
    null
  );
  let onPress = (
    e: PressEvent
  ) => {
    setClicked(
      e.target
        .textContent
    );
  };

  return (
    <LinkContext.Provider
      value={{ onPress }}
    >      {children}
      {clicked &&
        `You clicked ${clicked}`}
    </LinkContext.Provider>
  );
}

Now any Link inside a Router will update the router state when it is pressed.

<Router>
  <ul>
    <li><Link>Breadcrumbs</Link></li>
    <li><Link>Button</Link></li>
    <li><Link>Calendar</Link></li>
  </ul>
</Router>
<Router>
  <ul>
    <li><Link>Breadcrumbs</Link></li>
    <li><Link>Button</Link></li>
    <li><Link>Calendar</Link></li>
  </ul>
</Router>
<Router>
  <ul>
    <li>
      <Link>
        Breadcrumbs
      </Link>
    </li>
    <li>
      <Link>
        Button
      </Link>
    </li>
    <li>
      <Link>
        Calendar
      </Link>
    </li>
  </ul>
</Router>

Hooks#

If you need to customize things further, such as customizing the DOM structure, you can drop down to the lower level Hook-based API. See useLink for more details.