Navigation

Link

Navigate or open external resources.

Rust
1use herogpui::components::link::Link;

Usage

Rust
1use herogpui::prelude::Link;
2
3Link::new("link-hover")
4    .label("Hover to see the underline")
5    .href("#")

Live HeroGPUI compiled to WebAssembly. Select any example without loading another WASM instance.

Anatomy

Rust types

Link

Link is assembled from these builders. The API reference lists each one.

Customization

Appearance builders and theme tokens Link uses.

Styling

Link styling
StyleDescription
flex + items_center + text_color(colors.link) + FontWeight::MEDIUM + small_radius + cursor_pointerThe stylesheet is the contract — the docs' Global CSS snippet still says `font-semibold`, but the rule is `font-medium`. `--link` defaults to `--foreground`. Is a block-level flex row with no gap of its own (`.link` has none), and `underline-offset-4` has no GPUI analogue.
hover/active StyleRefinement underline 1.5px via colors.mutedOnly the decoration colour changes between the two states; gpui panics on a second `hover` call, so each state's closure owns its whole underline.
icon(element) laid out as a plain root child; no gap, no default-icon spacingEm-sized icon box with a 60% resting opacity that fills on interaction. The `ms-1 pb-1.5` spacing belongs to `[data-default-icon=true]` alone — the childless built-in arrow, which does not draw. The port's `icon(element)` draws the caller's element as-is, flush against the label.

API reference

Builders

Link builders
BuilderTypeDefaultDescription
href(url)urlDestination for the anchor. GPUI has no in-app navigation graph, so `href` opens through the OS handler (`App::open_url`) on press.
is_disabled(bool)boolfalseDisables pointer and keyboard interaction: the disabled opacity, no pointer reach, and no tab stop.
label(text) / icon(element)text / AnyElementContent rendered inside the link. Composes it as the label text plus an optional icon element, ordered by where the icon belongs (orders `Link.Icon` among the children).
on_press(handler)handlerFired when the link is activated, in addition to opening `href`. The callback receives GPUI's ClickEvent.
auto_focus(bool)boolWhether the element should receive focus on render. A link is not otherwise a focus target here, so this also makes it one; a disabled link is skipped by Tab and must not grab focus either.
render(closure)closureOverrides the default element with a custom render function. GPUI has no props to spread onto a caller-built element, so the closure receives the interactive half alone (`isHovered`, `isPressed`, `isFocused`, `isFocusVisible`, `isDisabled`) and draws the content; the root keeps the `href`, `onPress`, focus and disabled wiring either way.
icon(element)AnyElementCustom icon content. A childless `Link.Icon` renders v3's built-in arrow with `data-default-icon="true"` and its `ms-1 pb-1.5` spacing, and that default arrow has no port path: `icon(element)` is the custom-children path only, so draws no icon at all without it. `icon_first(true)` moves the icon before the label the way v3's child ordering does.

Parts

Link parts
PartDescription
LinkRoot anchor on the `.link` BEM class: `relative inline-flex h-fit w-fit items-center rounded-xl font-medium text-link no-underline decoration-[1.5px]`. The text colour is the `--link` token and never changes state; is a block-level flex row (no inline-flex) that hugs its content.
Link`hit testing-none inline-flex size-[0.75em] shrink-0 items-center justify-center text-current opacity-60`, raised to full opacity on hover, press and focus. `[data-default-icon=true]` adds `ms-1 pb-1.5`, but that rule belongs only to the childless built-in arrow, which does not draw; `icon(element)` is the arbitrary-children path and gets no default-icon spacing. Draws the caller's element verbatim, flush against the label, without the em-sized box or the default 60% opacity.

States

Link states
BuilderStateDescription
hover(StyleRefinement underline) with colors.muted.alpha(0.5)HoveredTurns the 1.5px underline on with `decoration-muted/50`; the text colour never changes.
active(StyleRefinement underline) with colors.mutedPressedTakes the underline decoration to full `decoration-muted`.
tab_stop_handle + ring_if_focusedFocus visibleKeyboard focus displays the status-focused ring; `track_focus` is what puts the link in the tab order.
is_disabled + disabled_opacity + track_focus gated on interactivityDisabledStatus-disabled: the disabled opacity, no pointer reach, and no tab stop.