AnimationDirectiveCSSAdded in v15.7

Spotlight

A soft circle of light sits under the pointer on a card's surface and follows it, and the card's border brightens a little near it. When the pointer leaves, the light fades out where it was. It has no inputs: the colour, the reach and the strength are CSS variables.

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 { WrSpotlight } from 'ngwr/animations/spotlight';

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

Basic

Put wrSpotlight on a positioned card; wr-card is one. The directive feeds two numbers and one state, and the stylesheet paints: two pseudo-elements, the light and the ring, cover the border box at z-index: -1 inside the host's own stacking context, so they paint over the card's background and border and under everything the card holds, and take no pointer. The point is read once per animation frame however many moves came in, and the host is measured at enter and on scroll or resize, never per move.

<wr-card wrSpotlight>
  <h3>Signals first</h3>
  <p>Every input, output and state is a signal.</p>
</wr-card>

Colour, reach, strength and ring

--wr-spotlight-color is the light's colour, primary by default: a role, never a step. --wr-spotlight-radius and -ring-radius are how far the light and the brighter border reach, -strength and -ring-strength how much of the colour each carries, and --wr-spotlight-edge the host's border width, so the ring is exactly as thick as the line it brightens. Each card below changes one thing.

<wr-card wrSpotlight style="--wr-spotlight-color: var(--wr-color-success)">…</wr-card>
<wr-card wrSpotlight style="--wr-spotlight-radius: 120px; --wr-spotlight-ring-radius: 90px">…</wr-card>
<wr-card wrSpotlight style="--wr-spotlight-strength: 30%">…</wr-card>
<wr-card wrSpotlight style="--wr-spotlight-strength: 0%; --wr-spotlight-ring-strength: 100%; --wr-spotlight-ring-radius: 260px">…</wr-card>

Accessibility

PartBehaviour
Keyboard Focus inside the card, with no pointer over it, is the stylesheet's own :focus-within rule: the same light at the centre, at half strength, so a keyboard user gets the same hint. A pointer inside wins.
Screen readersNothing is added to the card: the light is two pseudo-elements, and the host keeps its own name.
TouchA touch pointer is ignored: it has no hover, and a tap would leave the light on.
Reduced motion The light following the pointer is a pointer response, not motion, so it stays; only the fade in and out goes. Under forced-colors: active nothing listens, since the stylesheet paints nothing.
ServerNothing runs: the listeners are added after the first render, in the browser only.

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/spotlight declares each default on its own element.

VariableDefaultDeclared on
--wr-spotlight-colorvar(--wr-color-primary).wr-spotlight
--wr-spotlight-edge1px.wr-spotlight
--wr-spotlight-fadevar(--wr-transition-long).wr-spotlight
--wr-spotlight-radius240px.wr-spotlight
--wr-spotlight-ring-radius180px.wr-spotlight
--wr-spotlight-ring-strength60%.wr-spotlight
--wr-spotlight-strength12%.wr-spotlight
--wr-spotlight-x50%.wr-spotlight
--wr-spotlight-y50%.wr-spotlight

See also