Tessina UI
Tessina UI
GitHubIntroduction
InstallationUsageTheming
Components
ButtonIconButtonLinkSpinnerBadgeAvatarStatusChipShortcutSkeletonSurfaceProgressMeterRating
LabelFieldFieldsetCheckboxRadioSwitchSliderSelectComboboxSearchTextareaNumberFieldDate PickerTime PickerOTP InputFile UploadCalendar
AlertBannerToastTooltip
TabsAccordionCollapsibleBreadcrumbPaginationStepperSegmentedControlButtonGroupToggleButtonToggleGroupToolbarNavigation MenuMenubarBottom NavSidebar
Split ButtonFABDropdown MenuContextMenuCommandPopoverHoverCard
ContainerStackFlexGridAspectRatioSpacerCardCarouselDividerScroll Area
Table
ChatBubblePromptInputCodeBlock
ModalAlertDialogDrawerAction SheetTop Header MobileTop Header DesktopEmptyStateForm
Contributing
ComponentsEssentials

Link

A semantic anchor primitive for navigation, inline prose, and CTAs. Three variants, five sizes, five intents, three tones, configurable underline, external link handling, leading/trailing icons, and RTL support.

Playground

Installation

pnpm add @tessinaui/ui

Usage

import { Link } from "@tessinaui/ui";
<Link href="/docs">Read the documentation</Link>

<Link variant="standalone" trailingIcon={<ArrowRight />} href="/pricing">
  See pricing
</Link>

<Link external href="https://tessinaui.com">Tessina UI</Link>

Showcase

Variants

VariantDefault underlineWhen to use
inlinealwaysAnchors inside a sentence or paragraph — the default
standalonehoverNavigation links, CTAs sitting outside prose
quietnoneSubtle links that inherit the surrounding colour

Each variant sets a sensible underline default. You can override it explicitly with underline="always" \| "hover" \| "none" at any time.

Sizes

Mirrors Button and Field sizing so links line up with adjacent UI.

SizeText classIcon sizeUse case
xstext-xs14pxDense UI, filter rails
smtext-sm16pxCompact layouts
mdtext-base16pxDefault — body copy
lgtext-lg20pxLarge CTAs, settings
xltext-xl24pxHero links, marketing pages

Intents

Use intent to communicate meaning via colour. Any non-none intent overrides the tone choice for the default/muted tones; on-color intents stay tinted for dark surfaces.

IntentTokenTypical use
nonetext-primaryDefault brand link
errortext-errorDestructive or error context
warningtext-warningCaution
successtext-successConfirmation
infotext-infoInformational

Tones

ToneDefault colourUse case
defaulttext-primary (brand)Standard on light/background surfaces
mutedtext-muted-foregroundDe-emphasised links (e.g. footers)
on-colortext-backgroundDark surfaces, inverted themes

Underline

underline is orthogonal to variant — each variant has a sensible default, but you can pin the behaviour explicitly.

<Link underline="always">Always underlined</Link>
<Link underline="hover">Underline on hover</Link>
<Link underline="none">Never underlined</Link>

External links

Pass external to flag a link as external. Tessina Link then:

  • sets target="_blank" (unless you pass an explicit target)
  • sets rel="noopener noreferrer" (unless you pass an explicit rel)
  • appends an ExternalLink trailing icon

Turn the icon off with showExternalIcon={false}.

<Link external href="https://tessinaui.com">
  Tessina UI
</Link>

<Link external showExternalIcon={false} href="https://tessinaui.com">
  Tessina UI
</Link>

Icons

<Link variant="standalone" leadingIcon={<ArrowLeft />} href="/projects">
  Back to projects
</Link>

<Link variant="standalone" trailingIcon={<ArrowRight />} href="/pricing">
  See pricing
</Link>

Icons are wrapped in an aria-hidden span and sized by size. A custom trailingIcon overrides the auto external icon.

Disabled

<Link disabled href="/billing">
  Billing portal
</Link>

disabled visually mutes the link, sets aria-disabled="true", removes it from the tab order via tabIndex={-1}, and strips the href so it can't be navigated.

Integrating with Next.js / React Router

Use the render prop to inherit Tessina Link styling while preserving your router's navigation semantics.

import NextLink from "next/link";

<Link render={<NextLink href="/dashboard" />}>Dashboard</Link>
import { NavLink } from "react-router-dom";

<Link render={<NavLink to="/dashboard" />}>Dashboard</Link>

RTL

Pass dir="rtl" to flip icon order and spacing via logical-flow properties.

<Link dir="rtl" variant="standalone" leadingIcon={<ArrowLeft />} href="#">
  عودة إلى المشاريع
</Link>

Accessibility

  • Renders a native <a> element with the correct role, focus ring, and keyboard behaviour.
  • External links get rel="noopener noreferrer" automatically.
  • Disabled links set aria-disabled="true" and are removed from the tab order.
  • Keep link labels descriptive — "Read the full post" beats "click here".
  • When a link looks like a button, consider using Button with render={<a href="..." />} instead — buttons and links have different semantics.

API Reference

Link

PropTypeDefaultDescription
variant"inline" | "standalone" | "quiet""inline"Style personality. Drives the default underline and weight.
size"xs" | "sm" | "md" | "lg" | "xl""md"Size scale
intent"none" | "error" | "warning" | "success" | "info""none"Validation / meaning colour
tone"default" | "muted" | "on-color""default"Base colour tone
weight"normal" | "medium" | "semibold"variant-basedFont weight. Inline links default to normal; others to medium.
underline"always" | "hover" | "none"variant-basedUnderline behaviour. Overrides the variant default.
externalbooleanfalseOpens in a new tab with rel="noopener noreferrer" and shows an external icon.
showExternalIconbooleantrueHide the auto-added external icon when external is true.
leadingIconReactNode—Icon rendered before the label
trailingIconReactNode—Icon rendered after the label. Overrides the auto external icon when provided.
disabledbooleanfalseVisually mute the link, set aria-disabled, remove href, and drop from tab order
renderReactElement—Wraps another element (e.g. <NextLink>) to inherit Link styling
dir"ltr" | "rtl"—Text direction
hrefstring—Native href attribute
targetstring—Native target. Falls back to _blank when external is true.
relstring—Native rel. Falls back to noopener noreferrer when external is true and target="_blank".
classNamestring—Extra classes on the root <a> element

The component extends all standard <a> HTML attributes.

IconButton

A square button that renders a single icon, with optional external label and notification badge.

Spinner

Animated loading indicators with ring, dots, and pulse variants, five sizes, intent colors including brand primary, optional track, label positions, and LTR/RTL support.

On this page

PlaygroundInstallationUsageShowcaseVariantsSizesIntentsTonesUnderlineExternal linksIconsDisabledIntegrating with Next.js / React RouterRTLAccessibilityAPI ReferenceLink