AnimationDirectiveCSSAdded in v15.7

Glow Border

A short arc of brand light runs round the host's edge for ever, with a soft glow spilling outward. CSS does all of it; the directive only decides whether the arc turns.

Installation

Import the class, and @use the entry point in your global styles. Nothing warns you when the @use is missing.

import { Component } from '@angular/core';
import { WrGlowBorder } from 'ngwr/animations/glow-border';

@Component({ imports: [WrGlowBorder] })
export class MyComponent {}

Basic

Put wrGlowBorder on a positioned element; wr-btn is one. Two pseudo-elements carry one conic gradient turned by a registered angle: the arc itself, masked down to the ring, and a wider, blurred copy under the host, so only what spills past the edge shows. The host's own hover and focus states are untouched, and its focus ring paints above the arc.

<a wr-btn outlined size="lg" routerLink="/docs" wrGlowBorder>Get started</a>

The parent

The blurred copy sits at a negative z-index, so the host's stacking parent isolates itself to keep that copy above the page background. The host itself must not form a stacking context, or the copy would paint over its own fill.

.hero {
  position: relative;
  isolation: isolate;
}

Stopping the arc

active stops the arc without removing the directive: the ring stays lit and still. The same still ring is what a reader with reduced motion sees, and what a hidden tab holds.

<button wr-btn outlined type="button" wrGlowBorder [active]="live()">Stop and start</button>

Colours

--wr-glow-border-color is the arc's centre, primary by default; -warm and -cool, the two edges, are mixed from it toward danger and success, so one hook recolours the whole arc. Set it to a theme role on the host or above it: an intent for a call to action, the muted ink for a quiet ring.

<button wr-btn outlined type="button" wrGlowBorder>Primary</button>
<button wr-btn outlined type="button" wrGlowBorder style="--wr-glow-border-color: var(--wr-color-success)">Success</button>
<button wr-btn outlined type="button" wrGlowBorder style="--wr-glow-border-color: var(--wr-color-danger)">Danger</button>
<button wr-btn outlined type="button" wrGlowBorder style="--wr-glow-border-color: var(--wr-color-on-surface-muted)">Neutral</button>

Ring, glow and period

--wr-glow-border-width is the ring, --wr-glow-border-blur and -strength the glow that spills past the edge, and --wr-glow-border-period one turn, 4.5 s unset.

<button wr-btn outlined type="button" wrGlowBorder style="--wr-glow-border-width: 2px; --wr-glow-border-strength: 0.9; --wr-glow-border-period: 2s">
  Thicker, brighter, faster
</button>

Accessibility

PartBehaviour
Screen readers Nothing is added to the host: no children, no attributes a reader hears. The arc is two pseudo-elements.
Reduced motionUnder prefers-reduced-motion: reduce the ring stays lit and still.
Hidden documentThe arc stops while the tab is hidden and turns again when it is visible.
ServerThe still ring is rendered; the turn starts in the browser.

API

NameDescriptionTypeDefault
activeStops the arc without removing the directive.booleantrue

CSS variables

Set these on the element itself, with a rule more specific than its Declared on selector. In a global stylesheet, put a class of yours on an ancestor it really has: <body> for an overlay panel, which renders outside your markup. In a component stylesheet the selector alone works, but only for an element in that component's own template. A value on a wrapper or :root is shadowed, because ngwr/animations/glow-border declares each default on its own element.

VariableDefaultDeclared on
--wr-glow-border-blur14px.wr-glow-border
--wr-glow-border-colorvar(--wr-color-primary).wr-glow-border
--wr-glow-border-coolcolor-mix(in oklch, var(--wr-glow-border-color) 70%, var(--wr-color-success)).wr-glow-border
--wr-glow-border-period4.5s.wr-glow-border
--wr-glow-border-strength0.6.wr-glow-border
--wr-glow-border-warmcolor-mix(in oklch, var(--wr-glow-border-color) 70%, var(--wr-color-danger)).wr-glow-border
--wr-glow-border-width1.5px.wr-glow-border

See also