Info
The <smart-info> component provides a small info icon that toggles a popover with a short tooltip text. It follows the Base + Standard + Wrapper pattern with an InjectionToken-based extension mechanism. It renders a default InfoStandardComponent which can be replaced via INFO_STANDARD_COMPONENT_TOKEN.
Usage
<span>Email address</span>
<smart-info [options]="options" />
Components
InfoComponent (<smart-info>)
Main wrapper component. Renders InfoStandardComponent by default. When INFO_STANDARD_COMPONENT_TOKEN is provided, renders the injected component via NgComponentOutlet.
InfoStandardComponent (<smart-info-standard>)
Default concrete implementation. Renders:
- a small SVG info icon (button),
- a popover shown while
isOpen()istrue, - Tailwind-styled container with
smart:dark:*dark-mode classes, - a
document:clicklistener that closes the popover on outside click.
InfoPresetComponent (<smart-info-preset>)
Styled variation that extends InfoBaseComponent and is a drop-in replacement for InfoStandardComponent. Register it via INFO_STANDARD_COMPONENT_TOKEN to restyle every <smart-info>, or use the <smart-info-preset> selector directly. It renders the Preline Tooltip look: a circular icon toggle plus a small tooltip bubble. Visibility is driven by Angular hover/focus ((mouseenter)/(mouseleave) + (focus)/(blur)) using the inherited isOpen signal and @if — Preline's JS plugin is not installed. It keeps the translated Preline visual classes, exposes a placement input ('top' (default) | 'bottom' | 'left' | 'right') for tooltip position, and renders role="tooltip" with aria-describedby wiring on the toggle. All classes are smart:-prefixed Tailwind with explicit dark: variants. The class recipes live in preset/preset-classes.util.ts (getInfoContainerClasses, getInfoToggleClasses, getInfoTooltipClasses).
Because
InfoComponentrenders injected components viaNgComponentOutlet(which passes inputs by canonical name),InfoPresetComponentoverridescssClassasinput<string>('')without theclassalias. Bind it as[cssClass]when using the<smart-info-preset>selector directly, or just passclasson<smart-info>(the wrapper forwards it). Theplacementinput is only available on the preset selector directly — the<smart-info>wrapper forwards onlyoptionsandcssClass, so through the token tooltips default to'top'.
InfoBaseComponent (abstract)
Abstract base directive for extending custom info implementations. Exposes options, cssClass, isOpen signal, and toggle()/open()/close() methods.
API
Inputs
| Input | Type | Default | Description |
|---|---|---|---|
options | InputSignal<IInfoOptions> | required | Info configuration |
class | InputSignal<string> | '' | External CSS classes (alias for cssClass) |
IInfoOptions
The text value is rendered inside the popover through TranslatePipe, so it may be a translation key.
INFO_STANDARD_COMPONENT_TOKEN
InjectionToken that allows replacing the default InfoStandardComponent with a custom implementation. Provide a Type<InfoBaseComponent> to override.
Extending the base class
import {
ChangeDetectionStrategy,
Component,
computed,
ElementRef,
HostListener,
inject,
input,
ViewEncapsulation,
} from '@angular/core';
import { TranslatePipe } from '@ngx-translate/core';
import {
INFO_STANDARD_COMPONENT_TOKEN,
IInfoOptions,
InfoBaseComponent,
InfoComponent,
} from '@smartsoft001/angular';
@Component({
selector: 'docs-custom-info',
template: `
<div [class]="containerClasses()">
<button
type="button"
class="docs-info__trigger"
aria-label="More information"
[attr.aria-expanded]="isOpen()"
(click)="toggle(); $event.stopPropagation()"
>
?
</button>
@if (isOpen()) {
<div class="docs-info__popover" role="tooltip">
{{ options().text | translate }}
</div>
}
</div>
`,
imports: [TranslatePipe],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CustomInfoComponent extends InfoBaseComponent {
private readonly elementRef = inject(ElementRef);
// NgComponentOutlet passes 'cssClass' by canonical name, not the 'class'
// alias, so an info component registered through the token declares it
// explicitly.
override cssClass = input<string>('');
containerClasses = computed(() => {
const classes = ['docs-info'];
const extra = this.cssClass();
if (extra) classes.push(extra);
return classes.join(' ');
});
// InfoBaseComponent owns isOpen/toggle/open/close but does not close the
// popover on an outside click - a custom implementation adds that itself.
@HostListener('document:click', ['$event'])
onDocumentClick(event: MouseEvent): void {
if (!this.elementRef.nativeElement.contains(event.target)) {
this.close();
}
}
}
@Component({
selector: 'docs-info-custom-example',
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [InfoComponent],
// The token swaps the standard info popover for the custom one everywhere
// below this component, so consumers keep writing `<smart-info>`.
providers: [
{ provide: INFO_STANDARD_COMPONENT_TOKEN, useValue: CustomInfoComponent },
],
template: `
<label class="docs-info__label">Email address</label>
<smart-info [options]="options" />
`,
})
export class InfoCustomExampleComponent {
options: IInfoOptions = { text: 'Enter your primary email address.' };
}
Source
The component lives in packages/shared/angular/src/lib/components/info and is documented for Claude Code by the angular-components-info skill.