active-element
Track the focused element of a document.
| Package | @vizejs/composable/active-element |
| Own the source | vize lib pull composable:active-element |
| Runtime exports | useActiveElement |
| Gzip budget | 1280 B |
Minimal setup
Use a Vue 3.5+ project with Vue SFC compilation configured (see Vite+ integration).
vp install @vizejs/composable
Import the entry directly. Call lifecycle-bound utilities inside <script setup> so cleanup follows the component scope; consult the runtime contract for this entry's SSR and hydration behavior.
import { useActiveElement } from "@vizejs/composable/active-element";
Try it
Show guidance for the focused profile field
Follow actual document focus to show contextual instructions for a small workshop profile form.
What to observe: Press Tab from Display name through Email address and Workshop note. The visible focused-field label and guidance follow each field. Focus display name moves focus back; Clear focus returns to the outside-field state.
useActiveElement returns a readonly shallow ref of the real focused Element, with null during SSR. It reads the document only after mounting and listens for capturing focus/blur events. The example recognizes only its own fields through useId-based owner markers. Other controls or a blurred field show the outside-field state. The default follows open shadow roots; this example uses native inputs. Document listeners are released with the component scope.
Compare the initial and interacted states


Copy the example
Save this complete SFC in your Vue project. Its public imports and source are the same ones executed in the preview.
<script setup lang="ts">
import { computed, useId, useTemplateRef } from "vue";
import { useActiveElement } from "@vizejs/composable/active-element";
const profileId = useId();
const nameInput = useTemplateRef<HTMLInputElement>("nameInput");
const active = useActiveElement();
const focusedField = computed(() =>
active.value?.getAttribute("data-profile-owner") === profileId
? active.value.getAttribute("data-profile-field")
: null,
);
const guidance = computed(() => {
if (focusedField.value === "Display name") return "Use the name you want on your workshop badge.";
if (focusedField.value === "Email address")
return "Use an address where you can receive workshop details.";
if (focusedField.value === "Workshop note") return "Write a note for the workshop organizer.";
return "Focus a profile field to see its guidance.";
});
function focusName(): void {
nameInput.value?.focus();
}
function clearFocus(): void {
if (active.value instanceof HTMLElement) active.value.blur();
}
</script>
<template>
<div class="composable-example">
<label :for="`${profileId}-name`">Display name</label>
<input
:id="`${profileId}-name`"
ref="nameInput"
autocomplete="nickname"
:data-profile-owner="profileId"
data-profile-field="Display name"
:aria-describedby="`${profileId}-guidance`"
/>
<label :for="`${profileId}-email`">Email address</label>
<input
:id="`${profileId}-email`"
type="email"
autocomplete="email"
:data-profile-owner="profileId"
data-profile-field="Email address"
:aria-describedby="`${profileId}-guidance`"
/>
<label :for="`${profileId}-note`">Workshop note</label>
<input
:id="`${profileId}-note`"
:data-profile-owner="profileId"
data-profile-field="Workshop note"
:aria-describedby="`${profileId}-guidance`"
/>
<output aria-live="polite"
>Focused field: {{ focusedField || "Outside the profile fields" }}</output
>
<p :id="`${profileId}-guidance`">{{ guidance }}</p>
<div class="example-actions">
<button type="button" @click="focusName">Focus display name</button>
<button type="button" @click="clearFocus">Clear focus</button>
</div>
<p>Press Tab through the fields. The guidance follows the document's actual focused element.</p>
</div>
</template>
Runtime contract
| Utility | Category | Stability | SSR | Hydration | Cleanup | Targets | Host globals | Uses |
|---|---|---|---|---|---|---|---|---|
useActiveElement |
dom | experimental | deterministic-fallback | stable | reactive-scope | web, desktop | document |
tryOnScopeDispose |
API
useActiveElement
Track the focused element of a document. Listens for capturing focus/blur events on the document, so focus changes anywhere (including inside shadow trees) update the ref. Server renders expose null. Listeners are removed with the owning scope.
function useActiveElement( options: UseActiveElementOptions = {}, ): Readonly<ShallowRef<Element | null>>
Types
ActiveElementHost
Document-like capability observed by useActiveElement.
| Member | Type | Description |
|---|---|---|
activeElement |
Element | null |
Currently focused element. |
UseActiveElementOptions
Options for useActiveElement.
| Member | Type | Description |
|---|---|---|
deep? |
boolean |
Descend into open shadow roots to report the innermost focused element. |
host? |
MaybeRefOrGetter<ActiveElementHost | null | undefined> |
Reactive document capability for alternate runtimes and tests. |