Primitives
Preview the content behind a link on hover or keyboard focus. Also known as a hover card or link preview.
Import the Preview Card primitives from ng-primitives/preview-card.
import {
NgpPreviewCard,
NgpPreviewCardTrigger,
NgpPreviewCardArrow,
} from 'ng-primitives/preview-card';
Assemble the directives in your template. The trigger should be a link, or another control that still works without the card.
<a href="https://angularprimitives.com" [ngpPreviewCardTrigger]="card">Angular Primitives</a>
<ng-template #card>
<div ngpPreviewCard>Preview content</div>
</ng-template>
A tooltip labels a control with a short piece of text. A popover holds content the user works with: it opens on click and traps focus. A preview card opens on hover or keyboard focus like a tooltip, holds rich content like a popover, and leaves focus on the trigger.
A preview card is not exposed to assistive technology and cannot be opened on touch, so use a popover if the content matters.
Create a preview card component that uses the NgpPreviewCard directive.
Generate a reusable preview card component using the Angular CLI.
ng g ng-primitives:primitive preview-card
path: The path at which to create the component file.prefix: The prefix to apply to the generated component selector.component-suffix: The suffix to apply to the generated component class name.file-suffix: The suffix to apply to the generated component file name. Defaults to component.styles: How component styles should be generated. css (default) includes the full example styles; unstyled omits them entirely so you can style the component yourself.example-styles (deprecated): still supported for compatibility - true maps to styles: css, false maps to styles: unstyled.The open delay is long by default so that cards do not appear while the pointer crosses a page of links.
Add ngpPreviewCardArrow inside the card to point back at the trigger.
The following directives are available to import from the ng-primitives/preview-card package:
Place ngpPreviewCardArrow inside the card. It receives inset-inline-start or inset-block-start to position it against the trigger, so it must be positioned absolutely. Style it per side with data-placement:
[ngpPreviewCardArrow][data-placement='top'] {
/* Arrow styles when the card is positioned on top */
}
For the preview card to be positioned correctly relative to the trigger, it must use absolute or fixed positioning:
[ngpPreviewCard] {
position: absolute;
}
data-enter and data-exit are applied while the card is entering and leaving the DOM. Animate from the trigger with --ngp-preview-card-transform-origin.
[ngpPreviewCard][data-enter] {
animation: fade-in 0.15s ease-out;
}
[ngpPreviewCard][data-exit] {
animation: fade-out 0.12s ease-out;
}
You can configure the default options for all preview cards in your application by using the providePreviewCardConfig function in a providers array.
import { providePreviewCardConfig } from 'ng-primitives/preview-card';
bootstrapApplication(AppComponent, {
providers: [
providePreviewCardConfig({
placement: 'bottom',
offset: 4,
showDelay: 600,
hideDelay: 300,
flip: true,
container: 'body',
scrollBehavior: 'reposition',
cooldown: 300,
}),
],
});
There is no WAI-ARIA pattern for this behaviour. A preview card is a visual enhancement for sighted pointer and keyboard users only.
The card is deliberately not exposed to assistive technology: the content carries no role, and the trigger receives no aria-expanded, aria-haspopup, aria-controls or aria-describedby. Announcing a rich, interactive card as a link's description is worse than saying nothing, and aria-expanded would advertise a disclosure that cannot be operated by keyboard.
That constrains how it can be used:
Copyright © 2026 Angular Primitives
This site is powered by Netlify