Link
Anchor styled to the kit's conventions, for navigation or for an in-place action. It renders a
Text as an <a>, so everything that shapes text — size, weight, truncation — comes from
there.
Use this when / not when
- Use to navigate, and for a low-emphasis action inside a sentence or a table cell.
- Not for the primary action of a screen or a dialog — that is
Button, which is sized, focusable and labelled for the job. - Not for a link that opens a menu:
LinkWithDropdown. - Not for text that does not act — plain
Texthas the same typography without the cursor and the hover underline.
Import
import { Link, LinkType } from "@onlyoffice/apps-ui-kit/components/link";
Also exported from the root barrel @onlyoffice/apps-ui-kit.
Needs ThemeProvider from @onlyoffice/apps-ui-kit/providers/theme above it in the tree. It
supplies the link colour, which otherwise falls back to plain black.
Stories
Default
A page link that opens its address in a new tab. Hover it to see the underline, and change any other prop live in the Controls panel below.
Page Links
Page links navigate to another address; hover the regular one to see the solid underline a page link grows. Bold page link (isBold), Hovered page link keeps the underline on without a pointer (isHovered), Semitransparent page link is drawn at half opacity (isSemitransparent).

Action Links
Action links run code in place instead of navigating, for filtering a list or opening a menu; hover the regular one to see the dashed underline that sets them apart from page links. The four links show the same states as the page links above.

All Variants
Page and action links side by side, to compare the two underlines and the states each type shares: bold, hovered and semitransparent.

Hovered State
The link shows its hover underline with no pointer over it, as it should inside a row that highlights its link while the whole row is hovered (isHovered).
Semitransparent State
The link at half opacity, to mark an entity that is pending or inactive while keeping it clickable (isSemitransparent).
With Text Overflow
A label longer than its 200px container stays on one line and ends with an ellipsis, so it cannot push the layout wider (isTextOverflow with truncate).
No Hover Effect
Hover the link: no underline appears, for a link whose surroundings already show that it is clickable (noHover).
With Tooltip
Hover the link to read what it opens, for a label too short to say it (title). The text appears in the app's shared tooltip, not the browser's native one, so it shows only where the app mounts RootTooltip.
Keyboard Accessible Action
Press Tab to reach the link: an action link has no address, so without a role and a tab stop the keyboard skips it and a screen reader does not announce it. Here it is announced as a button (role), sits in the Tab order (tabIndex) and runs its action from the keys the handler checks (onKeyDown).
Custom Color
Colour draws the eye to a link inside plain text: the label takes any CSS colour (color). The value accent uses the accent colour of the portal instead, which this Storybook does not define, so it is not shown here.
Text Decorations
A link inside a paragraph is easier to spot when it is underlined before the pointer reaches it. Underlined link keeps a solid underline, Dashed action link a dashed one (textDecoration); the line stays the same on hover.
Css Customization
Overridable variables set on a wrapper and on the link itself -- the variables are listed under CSS variables on this page.
Custom color link is a page link: it takes the colour from the wrapper, and on hover shows no underline (--link-hover-page-text-decoration). Custom action link is there for the variables an action link reads: hover it for a wavy underline (--link-hover-text-decoration); at rest it carries a dotted underline and a taller line (--link-text-decoration, --link-line-height, through its style prop). --link-display is not shown: in a column of links its effect cannot be seen.
Minimal example
import { Link } from "@onlyoffice/apps-ui-kit/components/link";
export function RoomLink({ id, name }: { id: string; name: string }) {
return <Link href={`/rooms/${id}`}>{name}</Link>;
}
Props
Inherited from TextProps
Declared by components/text and accepted here too.
Added by the wrapper the folder exports
The index module exports a wrapped component, so these are accepted on top of the props above.
Recipes
An action link
An action link has no href, and an anchor without one is neither focusable nor announced as
anything. Give it a role, a tab stop and a key handler, or use a Button.
import { Link, LinkType } from "@onlyoffice/apps-ui-kit/components/link";
export function ResendInvite({ resend }: { resend: () => void }) {
return (
<Link
type={LinkType.action}
role="button"
tabIndex={0}
onClick={() => resend()}
onKeyDown={(e) => {
if (e.key === "Enter" || e.key === " ") resend();
}}
>
Resend the invitation
</Link>
);
}
A long label in a narrow column
import { Link } from "@onlyoffice/apps-ui-kit/components/link";
export function FileLink({ href, name }: { href: string; name: string }) {
return (
<div style={{ width: 200 }}>
<Link href={href} isTextOverflow truncate title={name}>
{name}
</Link>
</div>
);
}
Behaviour the types don't state
isTextOverflowdoes not produce an ellipsis. It only setsdisplay: inline-block; max-width: 100%, which gives the label a width to be clipped against. The clipping itself comes fromtruncate, inherited fromText. One without the other does nothing visible.titlenever reaches the DOM. The folder exportswithTooltip(Link), and the wrapper consumestitleas the tooltip's text. Only a string produces a tooltip, and it shows only in an application that mountsRootTooltiponce — without it the hover does nothing.color="accent"depends on the portal. It resolves tovar(--accent-main), which the portal's theme defines and this component does not; where nothing defines it, the declaration is dropped and the label takes its parent's colour.- The hover underline differs by type: a
pagelink grows a solid underline, anactionlink a dashed one.isHoveredholds that underline on without the pointer, andnoHoverremoves it in both cases. - An action link is not keyboard-operable by itself. With
type={LinkType.action}there is nohref, so the anchor has no implicit role, no tab stop and no Enter activation. The recipe above adds all three. aria-labelfalls back tochildrenwhenariaLabelis absent and the child is a string, so the visible text is the accessible name. A node child sets noaria-label, and the anchor is named by its content as any anchor is.labelis accepted and never read. The text ischildren;labelis spread onto the anchor as an unknown attribute.enableUserSelectdefaults to true, so the label is selectable unless you turn it off — the opposite of most controls in this kit.- The component is memoised with a deep comparison rather than React's shallow one, so a new object or handler on every render does not re-render it.
CSS variables
The other --link-* names in the stylesheet — --link-text-decoration (the line at rest,
none), --link-line-height (calc(100% + 6px)) and --link-display (inline-block, read
only while isTextOverflow is set) — are assigned on the component's own element, so a value
set on an ancestor is overridden. Set them through the link's own style prop, or use
textDecoration, lineHeight and isTextOverflow instead.
Accessibility
- With
hrefit is an ordinary anchor: focusable, activated by Enter, announced as a link. - With
type={LinkType.action}and nohrefit is none of those things until you passrole,tabIndexandonKeyDown. This is the component's sharpest edge. aria-labelis set fromariaLabel, or fromchildrenwhen that is a string.- The hover state is an underline; nothing distinguishes focus from hover, so a focus ring of your own is worth adding where a link is the only control in a row.
Test ids
Related
Button— for an action with emphasis, focus and a real button role.LinkWithDropdown— for a link that opens a menu.Text— the typography this component is built on.