Skip to content
PorabuildHeroGPUI component library
v0.14.0 · Apache-2.0

Navigation

Link

Navigate or open external resources.

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

Link on docs.rsSource at v0.14.0

Usage

Showing Usage, live: HeroGPUI compiled to WebAssembly. The canvas has no accessibility tree; each example's description and code below carry the same information.

Usage

`radius(px)` replaces the root's default `rounded-xl`; the link paints no fill of its own, so this one carries an `sx` background to show the corner. An element expression with window: &mut Window and cx: &mut App in scope.

Rust
use herogpui::prelude::Link;
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;

gpui::div()
    .flex()
    .flex_col()
    .items_start()
    .justify_center()
    .gap(px(12.))
    .children(vec![Link::new("link-hover")
        .label("Hover to see the underline")
        .href("#")
        .radius(px(4.))
        .sx(|el| el.bg(gpui::rgba(0x22c55e33)))
        .into_any_element()])

Icon Placement

An element expression with window: &mut Window and cx: &mut App in scope.

Rust
use herogpui::prelude::{ActiveTheme, Link, icons};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;

gpui::div()
    .flex()
    .flex_col()
    .items_start()
    .justify_center()
    .gap(px(12.))
    .children(vec![
        Link::new("link-icon-end")
            .label("Icon at end (default)")
            .icon(gpui::svg()
                      .size(px(16.))
                      .path(icons::EXTERNAL_LINK)
                      .text_color(cx.colors().foreground)
                      .into_any_element())
            .href("#")
            .into_any_element(),
        Link::new("link-icon-start")
            .label("Icon at start")
            .icon(gpui::svg()
                      .size(px(16.))
                      .path(icons::EXTERNAL_LINK)
                      .text_color(cx.colors().foreground)
                      .into_any_element())
            .icon_first(true)
            .href("#")
            .into_any_element(),
    ])

Text Decoration

The pinned `.link` carries `no-underline decoration-[1.5px]`; hover recolours the decoration to `decoration-muted/50` and press to `decoration-muted`. The text colour itself never changes state; a different decoration is the caller's own styling on the element they own. An element expression with window: &mut Window and cx: &mut App in scope.

Rust
use herogpui::prelude::Link;
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;

gpui::div()
    .flex()
    .flex_col()
    .items_start()
    .justify_center()
    .gap(px(12.))
    .children(vec![
        Link::new("link-decor")
            .label("Underlined on hover")
            .href("#")
            .into_any_element(),
    ])

Custom Icon

An element expression with window: &mut Window and cx: &mut App in scope.

Rust
use herogpui::prelude::{ActiveTheme, Link, icons};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;

gpui::div()
    .flex()
    .flex_col()
    .items_start()
    .justify_center()
    .gap(px(12.))
    .children(vec![Link::new("link-custom-icon")
        .label("Open the docs")
        .icon(gpui::svg()
                  .size(px(16.))
                  .path(icons::ARROW_RIGHT)
                  .text_color(cx.colors().foreground)
                  .into_any_element())
        .href("#")
        .into_any_element()])

Render Function

The `render` closure hands the link's interactive state to a caller-built element. The root keeps the `href`, press, focus and disabled wiring, and the closure draws the content from the state alone. An element expression with window: &mut Window and cx: &mut App in scope.

Rust
use herogpui::prelude::Link;
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;

gpui::div()
    .flex()
    .flex_col()
    .items_start()
    .justify_center()
    .gap(px(12.))
    .children(vec![
        Link::new("link-render")
            .href("#")
            .render(|state| {
                gpui::div()
                    .flex()
                    .items_center()
                    .gap(px(6.))
                    .child("Call to action")
                    .child(gpui::div().text_size(px(12.)).opacity(0.6).child(
                        if state.is_hovered {
                            "hovered"
                        } else if state.is_pressed {
                            "pressed"
                        } else if state.is_focus_visible {
                            "focus-visible"
                        } else if state.is_focused {
                            "focused"
                        } else if state.is_disabled {
                            "disabled"
                        } else {
                            "custom render"
                        },
                    ))
                    .into_any_element()
            })
            .into_any_element(),
    ])

Anatomy

Rust types

Link

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

API reference

Against HeroUI v3.2.6: 6 entries ported, 7 partial, 5 not ported. Partial rows are marked in the tables; entries not ported are listed under each table with the reason.

Builders

Link builders
BuilderValuesDefaultDescription
href(url)Partialstring—Destination 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)true | falsefalseDisables pointer and keyboard interaction: the disabled opacity, no pointer reach, and no tab stop.
label(text) / icon(element)PartialAnyElement—Content 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)PartialFn(e: ClickEvent) -> ()—Fired when the link is activated, in addition to opening `href`. The callback receives GPUI's ClickEvent.
auto_focus(bool)true | false—Whether 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)Partialrender closure<LinkRenderProps>—Overrides 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)PartialAnyElement—Custom 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.
Not ported5 HeroUI entries not ported
Link builders not ported
HeroUI v3Why it is not ported
Link.targetWhere to open the linked document. Has no browser navigation or HTTP transport — `href` opens through the OS handler — so there is nothing for a target to control.
Link.relRelationship between the documents. Meaningless without an anchor element handed to a browser; the OS handler receives only the URL string.
Link.downloadPrompts a file download. The OS handler decides what to do with the URL; has no HTTP transport to fetch and save it.
Link.classNameCustom classes merged with the default styles.
Link.Icon.className

Parts

Link parts
PartDescription
LinkPartialRoot 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.
LinkPartial`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
StateBuilderDescription
Hoveredhover(StyleRefinement underline) with colors.muted.alpha(0.5)Turns the 1.5px underline on with `decoration-muted/50`; the text colour never changes.
Pressedactive(StyleRefinement underline) with colors.mutedTakes the underline decoration to full `decoration-muted`.
Focus visibletab_stop_handleKeyboard focus displays the status-focused ring; `track_focus` is what puts the link in the tab order.
Disabledis_disabledStatus-disabled: the disabled opacity, no pointer reach, and no tab stop.