Link

A styled anchor component for navigation with built-in icon support

Import

import { Link } from '@heroui/react';

Usage

import {Link} from "@heroui/react";

export function LinkBasic() {
  return (
    <Link href="#">
      Call to action
      <Link.Icon />
    </Link>
  );
}

Anatomy

Import the Link component and access all parts using dot notation.

import { Link } from '@heroui/react';

export default () => (
  <Link href="#">
    Call to action
    <Link.Icon />
  </Link>
);

Custom Icon

import {Link} from "@heroui/react";
import {Icon} from "@iconify/react";

export function LinkCustomIcon() {
  return (
    <div className="flex flex-col gap-3">
      <Link href="#">
        External link
        <Link.Icon className="ml-1.5 size-3">
          <Icon icon="gravity-ui:arrow-up-right-from-square" />
        </Link.Icon>
      </Link>
      <Link className="gap-1" href="#">
        Go to page
        <Link.Icon className="size-3">
          <Icon icon="gravity-ui:link" />
        </Link.Icon>
      </Link>
    </div>
  );
}

Icon Placement

import {Link} from "@heroui/react";

export function LinkIconPlacement() {
  return (
    <div className="flex flex-col gap-3">
      <Link href="#">
        Icon at end (default)
        <Link.Icon />
      </Link>
      <Link className="gap-1" href="#">
        <Link.Icon />
        Icon at start
      </Link>
    </div>
  );
}

Underline Variants

Control the underline behavior with the underline prop:

Underline on hover (default)

Hover to see underline animation

Always visible underline

Underline always visible
import {Link} from "@heroui/react";

export function LinkUnderlineVariants() {
  return (
    <div className="flex flex-col gap-6">
      <div className="flex flex-col gap-2">
        <p className="text-muted text-sm font-medium">Underline on hover (default)</p>
        <Link href="#" underline="hover">
          Hover to see underline animation
          <Link.Icon />
        </Link>
      </div>

      <div className="flex flex-col gap-2">
        <p className="text-muted text-sm font-medium">Always visible underline</p>
        <Link href="#" underline="always">
          Underline always visible
          <Link.Icon />
        </Link>
      </div>

      <div className="flex flex-col gap-2">
        <p className="text-muted text-sm font-medium">No underline</p>
        <Link href="#" underline="none">
          Link without any underline
          <Link.Icon />
        </Link>
      </div>
    </div>
  );
}
  • underline="hover" (default) - Animated underline appears on hover
  • underline="always" - Underline always visible (50% opacity, 100% on hover)
  • underline="none" - No underline

Underline Offset

Adjust the spacing between text and underline with the underlineOffset prop:

import {Link} from "@heroui/react";

export function LinkUnderlineOffset() {
  return (
    <div className="flex flex-col gap-4">
      <Link href="#" underline="hover" underlineOffset={1}>
        Offset 1 (default)
        <Link.Icon />
      </Link>
      <Link href="#" underline="hover" underlineOffset={2}>
        Offset 2
        <Link.Icon />
      </Link>
      <Link href="#" underline="hover" underlineOffset={3}>
        Offset 3
        <Link.Icon />
      </Link>
    </div>
  );
}
  • underlineOffset={1} (default) - No space
  • underlineOffset={2} - 2px spacing
  • underlineOffset={3} - 4px spacing

Using with Routing Libraries

Use the asChild prop to compose Link with framework-specific links like Next.js:

import { Link } from '@heroui/react';
import NextLink from 'next/link';

export default function Demo() {
  return (
    <Link asChild underline="hover">
      <NextLink href="/about">
        About Page
        <Link.Icon />
      </NextLink>
    </Link>
  );
}

Direct Class Application

Since HeroUI uses BEM classes, you can apply Link styles directly to any link element without using asChild:

import NextLink from 'next/link';

// Apply classes directly
export default function Demo() {
  return (
    <NextLink href="/about" className="link link--underline-hover link--offset-1">
      About Page
    </NextLink>
  );
}

// Or with a native anchor
export default function NativeLink() {
  return (
    <a href="/about" className="link link--underline-always link--offset-2">
      About Page
    </a>
  );
}

Available BEM classes:

  • Base: link
  • Underline: link--underline-none, link--underline-hover, link--underline-always
  • Offset: link--offset-1, link--offset-2, link--offset-3

Styling

Passing Tailwind CSS classes

import { Link } from '@heroui/react';

function CustomLink() {
  return (
    <Link
      href="#"
      className="text-lg font-bold text-accent hover:text-accent/80"
    >
      Custom styled link
    </Link>
  );
}

Customizing the component classes

To customize the Link component classes, you can use the @layer components directive.
Learn more.

@layer components {
  .link {
    @apply font-semibold no-underline hover:underline;
  }
}

HeroUI follows the BEM methodology to ensure component variants and states are reusable and easy to customize.

CSS Classes

The Link component uses these CSS classes (View source styles):

Base Classes

  • .link - Base link styles

Underline Variants

  • .link--underline-none - No underline
  • .link--underline-hover - Animated underline on hover (default)
  • .link--underline-always - Always visible underline

Underline Offset

  • .link--offset-1 - No spacing (default)
  • .link--offset-2 - 2px spacing
  • .link--offset-3 - 4px spacing

Interactive States

The component supports both CSS pseudo-classes and data attributes for flexibility:

  • Focus: :focus-visible or [data-focus-visible="true"]
  • Disabled: :disabled or [aria-disabled="true"]

API Reference

PropTypeDefaultDescription
hrefstring-Destination URL for the anchor
targetstring"_self"Controls where to open the linked document
relstring-Relationship between the current and linked documents
downloadboolean | string-Prompts file download instead of navigation
underline"none" | "hover" | "always""hover"Controls underline visibility and behavior
underlineOffset1 | 2 | 31Spacing between text and underline
asChildbooleanfalseMerge props with child element (useful for routing libraries)
isDisabledbooleanfalseDisables pointer and keyboard interaction
classNamestring-Custom classes merged with the default styles
childrenReact.ReactNode-Content rendered inside the link
onPress(e: PressEvent) => void-Fired when the link is activated
autoFocusboolean-Whether the element should receive focus on render

Link.Icon Props

PropTypeDefaultDescription
asChildbooleanfalseMerge props with child element
childrenReact.ReactNode-Custom icon element; defaults to the built-in arrow icon when omitted
classNamestring-Additional CSS classes