The PlainLink is a foundational component with minimal styling used to build other link components in Pluma.

PlainLink

Usage

  • Use PlainLink to build custom hyperlinks that need a treatment Link doesn't support, such as wrapping a whole card, an icon-and-label group, or an image in a single clickable region.
  • Use Link instead when the element is a standard hyperlink or an inline action styled like one.
  • Use PlainButton instead of PlainLink when building a custom interactive element that needs its own visual design along with loading and disabled support.
  • Use Button instead when the element needs full built-in styling, variants, sizes, icons, or state treatments for a standard action.
  • Never nest other interactive elements (buttons, links) inside a PlainLink — it confuses users and breaks assistive technology and keyboard navigation. Keep PlainLink content static.

Types

  • Regular link (default, no as prop) — renders an anchor that navigates to a URL, downloads a file, or opens an email/phone link.
  • Button-like (as="button") — renders a button element to trigger an inline action while remaining unstyled.

Behaviors

  • Base state applies no styling of its own — it looks exactly like its passed content.
  • Disabled state (isDisabled) prevents interaction; provide the visual treatment (e.g., muted color) via the wrapped content, since PlainLink adds none itself.
  • Mark a link as external so users aren't unexpectedly taken to another site without warning. External detection is automatic based on the URL, or set it explicitly with isExternal.
  • External links open in a new tab with safe HTML attributes (rel="noopener noreferrer", target="_blank") applied automatically.

Content

  • Write labels that clearly describe the destination or action in 1-3 words.
  • Never use vague labels like "Click here" or "Learn more".
  • Follow the same content guidance as the Link component's labels.

Implementation Notes

  • Content pattern: React uses children; Ember uses the default yield block ({{yield}}).
  • href sets the destination URL; omit it entirely for the button type (as="button").
  • External detection (isExternalUrl in plain-link.utils.ts) treats http://, https://, mailto:, and tel: URLs as external. isExternal explicitly overrides auto-detection in either direction.
  • withSafeExternalAttributes (default true) controls whether target="_blank" rel="noopener noreferrer" are auto-added on external links. Set it to false for external-looking protocols that shouldn't open in a new tab, such as mailto: or tel: links.
  • replace is forwarded to the app's link-routing component (useLinkComponent/LinkComponentContext) to use replaceState instead of pushState. It only has an effect when PlainLink renders through that routing component — i.e., not as="button" and not an external link.
  • When isDisabled is true, href is not rendered, tabindex="-1" and aria-disabled="true" are set, and any click is prevented/stopped — but the HTML disabled attribute is also applied even on tags that don't natively support it.
  • PlainLink is polymorphic via the underlying Box component's as prop ('a' | 'button'). External links always force as="a" regardless of the as value passed in.
  • Ember: the component name is <PlumaPlainLink>; args map 1:1 to the React props (@href, @isDisabled, @isExternal, @withSafeExternalAttributes, @replace) plus any Box prop.

On this page