Frontile

ExternalLink

A link to another site, marked with an external-link icon.

It opens a new tab, adds rel="noopener noreferrer", and appends visually hidden text announcing the new tab — so a link that shows the icon always behaves the way the icon promises. For in-app navigation use TabNav or Ember's LinkTo.

Import

import { ExternalLink } from 'frontile';

Usage

Pass @href. Everything else has a default.

The anchor is display: inline, so a link wraps mid-phrase inside a paragraph like any other. The icon can end up alone on the next line when the break falls right after the last word.

import { ExternalLink } from 'frontile';

<template>
  <div class='not-prose text-neutral-strong max-w-xs p-2'>
    <p>
      Frontile is built on
      <ExternalLink @href='https://emberjs.com'>Ember Octane</ExternalLink>
      and styled with
      <ExternalLink @href='https://tailwindcss.com'>Tailwind CSS</ExternalLink>.
    </p>
  </div>
</template>

Color

The link inherits its color and font size from the surrounding text. Tint it with a text utility on @class.

import { ExternalLink } from 'frontile';

<template>
  <div class='not-prose flex flex-col items-start gap-3 p-2'>
    <span class='text-neutral-strong'>
      <ExternalLink @href='https://emberjs.com'>Inherited color</ExternalLink>
    </span>
    <ExternalLink @href='https://emberjs.com' @class='text-primary'>
      Primary
    </ExternalLink>
    <ExternalLink @href='https://emberjs.com' @class='text-danger'>
      Danger
    </ExternalLink>
    <p class='text-neutral text-sm'>
      The icon scales with the text, so
      <ExternalLink @href='https://emberjs.com'>a small link</ExternalLink>
      gets a small icon.
    </p>
  </div>
</template>

Underline

import { ExternalLink } from 'frontile';

<template>
  <div
    class='not-prose text-neutral-strong flex flex-col items-start gap-3 p-2'
  >
    <ExternalLink @href='https://emberjs.com'>
      Always underlined (default)
    </ExternalLink>
    <ExternalLink @href='https://emberjs.com' @underline='hover'>
      Underlined on hover
    </ExternalLink>
    <ExternalLink @href='https://emberjs.com' @underline='none'>
      Never underlined
    </ExternalLink>
  </div>
</template>

Icon placement

import { ExternalLink } from 'frontile';

<template>
  <div
    class='not-prose text-neutral-strong flex flex-col items-start gap-3 p-2'
  >
    <ExternalLink @href='https://emberjs.com'>Icon at the end (default)</ExternalLink>
    <ExternalLink @href='https://emberjs.com' @iconPlacement='start'>
      Icon at the start
    </ExternalLink>
  </div>
</template>

Pass @showIcon={{false}} to drop the icon. The new tab, the rel, and the screen-reader announcement stay.

import { ExternalLink } from 'frontile';

<template>
  <div class='not-prose text-neutral-strong p-2'>
    <ExternalLink @href='https://emberjs.com' @showIcon={{false}}>
      No icon
    </ExternalLink>
  </div>
</template>

Custom icon

The :icon block replaces the built-in glyph and keeps its size and spacing. Named blocks require an explicit :default block for the link text.

import { ExternalLink } from 'frontile';
import { ShareIcon } from 'site/components/icons';

<template>
  <div class='not-prose text-neutral-strong p-2'>
    <ExternalLink @href='https://emberjs.com'>
      <:default>Custom icon</:default>
      <:icon><ShareIcon /></:icon>
    </ExternalLink>
  </div>
</template>

Target and rel

@target defaults to _blank, and rel is then noopener noreferrer. Setting @target='_self' navigates in place: no rel is emitted and the new-tab announcement is dropped, since neither would be true.

@rel replaces the default outright — include noopener noreferrer yourself if the link still opens a new tab.

import { ExternalLink } from 'frontile';

<template>
  <div
    class='not-prose text-neutral-strong flex flex-col items-start gap-3 p-2'
  >
    <ExternalLink @href='https://emberjs.com'>New tab (default)</ExternalLink>
    <ExternalLink @href='https://emberjs.com' @target='_self'>
      Same tab
    </ExternalLink>
    <ExternalLink
      @href='https://emberjs.com'
      @rel='noopener noreferrer nofollow'
    >
      With nofollow
    </ExternalLink>
  </div>
</template>

Accessibility

The icon is aria-hidden, so its meaning is carried by visually hidden text after the link label: a screen reader announces "Ember.js (opens in a new tab)". Translate it with @newTabLabel, or pass an empty string to remove it when the surrounding copy already says so.

import { ExternalLink } from 'frontile';

<template>
  <div
    class='not-prose text-neutral-strong flex flex-col items-start gap-3 p-2'
  >
    <ExternalLink
      @href='https://emberjs.com'
      @newTabLabel='(abre em uma nova aba)'
    >
      Translated announcement
    </ExternalLink>
    <ExternalLink @href='https://emberjs.com' @newTabLabel=''>
      No announcement
    </ExternalLink>
  </div>
</template>

The announcement follows @target: a _self link never gets it. Give the link text that reads on its own — "Ember.js" rather than "click here" — since screen reader users often navigate by a list of links stripped of surrounding prose.

Keyboard behaviour is a plain anchor's: Tab to focus, Enter to follow. Focus shows the standard focus ring.

API

ExternalLink

Element: HTMLAnchorElement

A link to another site.

It opens a new tab, marks itself with an external-link glyph, protects the opener with rel="noopener noreferrer", and tells assistive technology that a new tab is coming — so the four cannot drift apart. For in-app navigation use TabNav or Ember's LinkTo.

Arguments

Name Type Default Description
href * string - The absolute URL to link to.
class string - Custom class name, it will override the default ones using Tailwind Merge library.
classes SlotsToClasses<'base' | 'icon'> - Custom CSS classes for styling the individual slots: base for the anchor, icon for the glyph wrapper.
iconPlacement enum 'end' Which side of the text the glyph sits on.
newTabLabel string '(opens in a new tab)' The visually-hidden text announced when the link opens a new tab. Pass an empty or blank string to suppress it.
rel string - Replaces the default rel. Left off, noopener noreferrer is applied whenever the link opens a new browsing context.
showIcon boolean true Set to false to drop the glyph. The target, rel and new-tab announcement are unaffected.
target enum '_blank' The browsing context to open in. Any frame name is accepted; the four keywords are listed so editors can complete them.
underline enum 'always'

Blocks

Name Type Default Description
default * Array - The link text.
icon * Array - Replaces the built-in glyph, keeping its size and spacing.
Released under MIT License - Created by Josemar Luedke