Skip to content
Lenso UI

Link

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

Usage

import { Link } from '@lenso/ui';
"use client";
import { Link } from "@lenso/ui";
export function LinkBasic() {  return (    <Link href="#">      Call to action <Link.Icon aria-hidden="true" />    </Link>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

Anatomy

import { Link } from '@lenso/ui';
export default () => (  <Link href="#">    Call to action    <Link.Icon />  </Link>);

Examples

Icon Placement

"use client";// Adapted from HeroUI v3.2.6 (e385ac2), Apache-2.0.import { Link } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";import { styles } from "./source.stylex";export function LinkIconPlacement() {  return (    <div {...stylex.props(styles.column)}>      <Link href="#">        Icon at end (default)        <Link.Icon />      </Link>      <Link href="#" xstyle={styles.gap}>        <Link.Icon />        Icon at start      </Link>    </div>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

Text Decoration with Tailwind CSS

Link is underlined on hover by default. Use Tailwind CSS text-decoration utilities to make the underline always visible, remove it entirely, or customize its color, style, thickness, and offset.

"use client";// Adapted from HeroUI v3.2.6 (e385ac2), Apache-2.0.import { Link } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";import { styles } from "./source.stylex";export function LinkUnderlineAndOffset() {  return (    <div {...stylex.props(styles.sections)}>      <div {...stylex.props(styles.section)}>        <p {...stylex.props(styles.caption)}>Default hover underline</p>        <Link href="#">          Hover to see the underline          <Link.Icon />        </Link>      </div>      <div {...stylex.props(styles.section)}>        <p {...stylex.props(styles.caption)}>Always visible underline</p>        <Link href="#" xstyle={styles.underline}>          Underline always visible          <Link.Icon />        </Link>      </div>      <div {...stylex.props(styles.section)}>        <p {...stylex.props(styles.caption)}>No underline</p>        <Link href="#" xstyle={styles.noUnderline}>          Link without any underline          <Link.Icon />        </Link>      </div>      <div {...stylex.props(styles.section)}>        <p {...stylex.props(styles.caption)}>Changing the underline offset</p>        <div {...stylex.props(styles.column)}>          {[styles.offset1, styles.offset2, styles.offset3, styles.offset4].map((offset, index) => (            <Link key={index} href="#" xstyle={offset}>              Offset {index + 1} ({index + 1}px space)              <Link.Icon />            </Link>          ))}        </div>      </div>    </div>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

Text Decoration Line:

  • underline - Always visible underline
  • no-underline - Remove underline
  • default Link styles - Underline appears on hover

Text Decoration Color:

  • decoration-accent, decoration-muted, etc. - Set underline color using theme colors
  • decoration-muted/50 - Use opacity modifiers for semi-transparent underlines

Text Decoration Style:

  • decoration-solid - Solid line (default)
  • decoration-double - Double line
  • decoration-dotted - Dotted line
  • decoration-dashed - Dashed line
  • decoration-wavy - Wavy line

Text Decoration Thickness:

  • decoration-1, decoration-2, decoration-4, etc. - Control underline thickness

Underline Offset:

  • underline-offset-1, underline-offset-2, underline-offset-4, etc. - Adjust spacing between text and underline

For more details, see the Tailwind CSS documentation:

Available BEM classes:

  • Base: link
  • Icon: link__icon

Custom Icon

"use client";// Adapted from HeroUI v3.2.6 (e385ac2), Apache-2.0.import { ArrowUpRightFromSquare, Link as LinkIcon } from "@gravity-ui/icons";import { Link } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";import { styles } from "./source.stylex";export function LinkCustomIcon() {  return (    <div {...stylex.props(styles.column)}>      <Link href="#">        External link        <Link.Icon xstyle={styles.marginIcon}>          <ArrowUpRightFromSquare />        </Link.Icon>      </Link>      <Link href="#" xstyle={styles.gap}>        Go to page        <Link.Icon xstyle={styles.icon}>          <LinkIcon />        </Link.Icon>      </Link>    </div>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

Render Function

"use client";// Adapted from HeroUI v3.2.6 (e385ac2), Apache-2.0. Native anchor retained through Base UI render composition.import { Link } from "@lenso/ui";export function RenderFunction() {  return (    <Link      href="#"      render={(props) => (        <a {...props} data-custom="foo">          {props.children}        </a>      )}    >      Call to action      <Link.Icon />    </Link>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

Customization

Tailwind CSS

"use client";// Adapted from HeroUI v3.2.6 (e385ac2), Apache-2.0.import { Link } from "@lenso/ui";import { styles } from "./source.stylex";export function CustomStyles() {  return (    <Link href="#" xstyle={styles.custom}>      Call to action      <Link.Icon />    </Link>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

Global CSS

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;  }}

Styling Reference

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 [!toc]

  • .link - Base link styles
  • .link__icon - Link icon styles

Interactive States

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

  • Focus: :focus-visible or [data-focus-visible="true"]
  • Hover: :hover or [data-hovered="true"]
  • Pressed: :active or [data-pressed="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
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
renderDOMRenderFunction<keyof React.JSX.IntrinsicElements, LinkRenderProps>-Overrides the default DOM element with a custom render function.

Link.Icon

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

Using with Routing Libraries

Use variant functions to style framework-specific links like Next.js:

import { Link } from '@lenso/ui';import { linkVariants } from '@lenso/tokens';import NextLink from 'next/link';
export default function Demo() {  const slots = linkVariants();
  return (    <NextLink className={slots.base()} href="/about">      About Page      <Link.Icon className={slots.icon()} />    </NextLink>  );}

Direct Class Application

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

import NextLink from 'next/link';
// Apply classes directly with Tailwind utilitiesexport default function Demo() {  return (    <NextLink href="/about" className="link hover:underline underline-offset-2">      About Page    </NextLink>  );}
// Or with a native anchorexport default function NativeLink() {  return (    <a href="/about" className="link underline decoration-accent underline-offset-4">      About Page      <Link.Icon className="link__icon" />    </a>  );}