Skip to main content

link — plain navigation

UiLink is an anchor: text (optionally with a leading icon) that takes the user somewhere. It is the quiet counterpart to action — no button chrome, no style, no confirm. Where an action does something, a link goes somewhere.

Reach for UiLink for back/next navigation, "View history", a footnote to external documentation, or the links row under a detail or form. Reach for a UiAction with appearance: LINK instead when the thing is really a command that merely wants to look understated.

Live — plain links, links with a leading icon, an external link that opens in a new tab, and "Load history", which carries an onClick trigger and patches the line below instead of navigating.

Fields

FieldTypeMeaning
idStringNode id and DOM id. The of(...) factories set it to rel for backwards compatibility.
relStringLink relation / role — e.g. back, next, ref. Historically doubled as the id slot.
hrefStringTarget URL. Falls back to # when absent. Also the no-JS / SSR target when onClick is set.
labelStringThe visible link text.
iconStringIcon token rendered before the label. See icons.
externalbooleanDefaults to false. true renders target="_blank" rel="noopener noreferrer" and always navigates natively.
onClickUiTriggerOptional click behaviour dispatched through the event bus instead of navigating. Ignored when external is true.
titleStringInherited from UiNode. Not rendered by the link renderer.
cssClassStringExtra CSS class added next to sui-link.

Building one

// Plain navigation — the id is set to the rel:
UiLink.of("back", "/products", "Back to products");

// With a leading icon:
UiLink.of("ref", "/products/42/manual.pdf", "Download the manual").icon("download");

// External — opens in a new tab, onClick would be ignored:
UiLink.external("ref", "https://example.com", "Vendor website");

// A link that fires a trigger through the bus; href stays as the no-JS target:
UiLink.of("ref", "/products/42/history", "Load history")
.onClick(UiTrigger.api("GET", "/products/42/history"));

// Where links usually live:
UiDetail.of("product-detail", "Product")
.link(UiLink.of("ref", "/products/42/history", "View history"));

Notes

Three renderings, one node. Without onClick the anchor gets a data-href hint and the bus routes it through the SPA. With onClick it gets a data-trigger and dispatches a fetch/patch, with inline loading painted on the link itself while the request is in flight — href remains as the plain-HTML fallback for SSR and no-JS. With external: true neither hint is emitted, so the native click goes through and target="_blank" actually works.

external wins over onClick. An external link always navigates natively; attaching a trigger to it has no effect. If you need a behaviour, drop external and open the tab yourself with UiTrigger.openInTab(url).

rel is not HTML's rel. It is the node's own relation slot — back, next, ref — and the of(...) factories copy it into id so that patch targets and the editor's id-based selection keep working with legacy trees. Give two links on the same page distinct rel values, or set the id explicitly.

Links come in rows, not alone. UiDetail and UiForm both carry a links list rendered in the footer next to the actions; that is where most links belong. A loose link inside a stack is fine for navigation chrome, but a run of them usually wants to be a menu.

See also

  • action — clickable things that do something.
  • detail — the links footer row.
  • icon — the token set available for icon.
  • Triggers cookbook — what an onClick can do.