ActiveElement
Reactive tracking of the currently focused element in the document. Wraps document.activeElement as an Angular signal.
Usage
import { Component } from '@angular/core';
import { activeElement } from '@signality/core';
@Component({
template: `
<input placeholder="Enter your name" />
<button>Submit</button>
<p>Active: {{ activeEl()?.tagName }}</p>
`,
})
export class ActiveElementDemo {
readonly activeEl = activeElement();
}Use InjectionToken for Singleton
For global state tracking like activeElement, consider using the provided ACTIVE_ELEMENT token instead of calling the function directly. This provides a singleton instance that can be shared across your entire application, reducing memory usage and event listener overhead:
import { inject } from '@angular/core';
import { ACTIVE_ELEMENT } from '@signality/core';
const activeEl = activeElement();
const activeEl = inject(ACTIVE_ELEMENT); Learn more about Token-based utilities.
Parameters
| Parameter | Type | Description |
|---|---|---|
options | ActiveElementOptions | Optional configuration (see Options below) |
Options
The ActiveElementOptions extends CreateSignalOptions<Element | null> and WithInjector:
| Option | Type | Description |
|---|---|---|
equal | ValueEqualityFn<Element | null> | Custom equality function (see more) |
debugName | string | Debug name for the signal (development only) |
injector | Injector | Optional injector for DI context |
Return Value
Returns a Signal<Element | null> that reflects the currently focused element. The value depends on the current focus state:
| Signal value | When |
|---|---|
Focused Element | An interactive element (input, button, link, [tabindex], etc.) has focus |
<body> | No interactive element has focus — the browser defaults activeElement to document.body |
null | The document itself has no focus (e.g. the browser window is blurred), or during SSR |
Shadow DOM
Unlike native document.activeElement, this utility traverses open Shadow DOM boundaries and returns the deepest focused element inside shadow trees. The native API would return the shadow host instead.
Examples
Focus indicator
import { Component, computed } from '@angular/core';
import { activeElement } from '@signality/core';
@Component({
template: `
<div class="form">
<input name="email" placeholder="Email" />
<input name="password" type="password" placeholder="Password" />
</div>
<p class="hint">{{ hint() }}</p>
`,
})
export class FocusHints {
readonly activeEl = activeElement();
readonly hint = computed(() => {
const el = this.activeEl();
if (!(el instanceof HTMLInputElement)) {
return '';
}
switch (el.name) {
case 'email': return 'Enter your email address';
case 'password': return 'Minimum 8 characters';
default: return '';
}
});
}Focus trap
A focus trap keeps keyboard focus confined within a specific region (e.g. a modal dialog) while it's open. Without it, pressing Tab would move focus outside the dialog — breaking keyboard navigation and accessibility. See the WAI-ARIA dialog pattern for the full spec.
import { Component, viewChild, ElementRef, effect } from '@angular/core';
import { activeElement } from '@signality/core';
@Component({
template: `
<div #modal class="modal">
<button #first>First</button>
<button>Middle</button>
<button #last>Last</button>
</div>
`,
})
export class FocusTrapModal {
readonly activeEl = activeElement();
readonly modal = viewChild<ElementRef>('modal');
readonly firstEl = viewChild<ElementRef>('first');
readonly lastEl = viewChild<ElementRef>('last');
constructor() {
effect(() => {
const modalEl = this.modal()?.nativeElement;
const activeEl = this.activeEl();
if (modalEl && activeEl && !modalEl.contains(activeEl)) {
// Focus escaped modal, bring it back
this.firstEl()?.nativeElement.focus();
}
});
}
}SSR Compatibility
On the server, the signal initializes with null.
Type Definitions
type ActiveElementOptions = CreateSignalOptions<Element | null> & WithInjector;
function activeElement(options?: ActiveElementOptions): Signal<Element | null>;Related
- ElementFocus — Track focus on specific element