---
title: Link
description: A styled link component with optional icon, underline effects, and smart text formatting for enhanced hover interactions.
---

```tsx
'use client';

import { Link } from '@/ui/Link';

export function LinkDemo() {
  return <Link label="Learn more about our services" href="#" icon="ArrowDefaultRight" />;
}
```

## Installation

Using the CLI:

```bash
npx shadcn@latest add https://develop.trident-ui.pro.clubmed/r/link.json
```

Or manually, copy the following code into `/ui/link.tsx`:

```tsx
import clsx from 'clsx';
import type { AnchorHTMLAttributes, FunctionComponent, PropsWithChildren } from 'react';

import { Icon, type IconicNames, type IconicTypes } from '@clubmed/trident-icons';
import { twMerge } from './helpers/twMerge';

interface LinkProps<T extends HTMLAnchorElement = HTMLAnchorElement>
  extends AnchorHTMLAttributes<T> {
  /**
   * Label text
   */
  label: string;
  /**
   * Icon name
   */
  icon?: IconicNames;
  iconType?: IconicTypes;
  /**
   * Icon width
   */
  width?: string;
  /**
   * Underlined
   */
  underlined?: boolean;
  /**
   * Additional class names
   */
  className?: string;
  /**
   * Is the link inert (not itself clickable but part of a clickable element)
   */
  inert?: boolean;
  /**
   * Allow giving a custom component
   */
  component?: FunctionComponent<PropsWithChildren<any>> | string;
}

export const Link: FunctionComponent<LinkProps> = ({
  label,
  icon,
  component = 'a',
  iconType,
  underlined = true,
  className,
  inert,
  width = '24px',
  ...anchorAttrs
}) => {
  if (!label) {
    return null;
  }
  const lastSpace = label.lastIndexOf(' ');
  const lastIndex = lastSpace === -1 ? label.length : lastSpace;

  const first = label.substring(0, 1);
  const middle = label.substring(1, lastIndex + 1);
  const last = label.substring(lastIndex);
  const Cmp = component as FunctionComponent<PropsWithChildren>;

  const TagName = inert ? 'span' : Cmp;

  return (
    <TagName
      className={twMerge(
        'decoration-none link-container cursor-pointer text-b3 font-semibold outline-none focus-visible:ring-4 focus-visible:ring-black focus-visible:ring-offset-2',
        className,
      )}
      data-name="Link"
      {...anchorAttrs}
    >
      <span className={clsx({ 'link-underline': underlined })}>{first}</span>
      <span
        className={clsx('hoverable', {
          'has-icon': icon,
          'link-underline': underlined,
        })}
      >
        {middle}
        <span className="inline-block">
          {last}
          {icon && (
            <Icon
              name={icon}
              iconType={iconType}
              width={width}
              style={{ marginInlineStart: '8px' }}
            />
          )}
        </span>
      </span>
    </TagName>
  );
};
```

## Usage

```tsx showLineNumbers
import Link from '@/docs/lib/ui/link';

export function Component() {
  return (
    <div>
      <Link label="View documentation" href="/docs" icon="ArrowDefaultRight" />
    </div>
  );
}
```

## API Reference

### Link

| Prop         | Type                                                  | Default     | Description                                                                                                                                                                |
| ------------ | ----------------------------------------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `label`      | `string`                                              | Required    | The text content of the link. This text is intelligently split to apply hover effects and accommodate icons.                                                               |
| `icon`       | `IconicNames`                                         | `undefined` | Optional icon to display after the link text. Icons from `@clubmed/trident-icons` library.                                                                                 |
| `iconType`   | `IconicTypes`                                         | `undefined` | The type/style of the icon to display (e.g., `"ArrowDefault"`, `"ArrowTail"`).                                                                                             |
| `width`      | `string`                                              | `"24px"`    | The width of the icon. Accepts any valid CSS width value.                                                                                                                  |
| `underlined` | `boolean`                                             | `true`      | Whether the link text should have an underline effect on hover.                                                                                                            |
| `className`  | `string`                                              | `undefined` | Additional CSS classes to apply to the link container. Merged with default classes using `tailwind-merge`.                                                                 |
| `inert`      | `boolean`                                             | `undefined` | If `true`, renders the link as a `<span>` instead of an anchor, making it non-clickable but styled as a link (useful when the link is part of a larger clickable element). |
| `component`  | `string \| FunctionComponent<PropsWithChildren<any>>` | `"a"`       | Custom component to render instead of the default anchor tag. Useful for integrating with routing libraries (e.g., Next.js `Link`, React Router `Link`).                   |

The Link component also accepts all standard HTML anchor attributes (e.g., `href`, `target`, `rel`, `onClick`) via `AnchorHTMLAttributes<HTMLAnchorElement>`.

## Notes

- **Smart Text Formatting**: The component intelligently splits the label text to apply special formatting. The first character and the last word (after the final space) receive hover effects for enhanced visual feedback.
- **Icon Integration**: When an icon is provided, it's positioned after the link text with an 8px inline-start margin for proper spacing.
- **Polymorphic Component**: Use the `component` prop to render the link with custom components like Next.js `Link` or React Router `Link` while maintaining the same styling and behavior.
- **Inert Mode**: The `inert` prop is useful when the link is nested inside another clickable element. It prevents event bubbling conflicts while maintaining visual consistency.
- **Underline Effects**: The default underline styling provides sophisticated hover interactions that work well with the text splitting logic.
- **Accessibility**: When using custom components via the `component` prop, ensure they maintain proper link semantics for screen readers and keyboard navigation.
