on-start-typing
Whether a keyboard event would type a printable character.
| Package | @vizejs/composable/on-start-typing |
| Own the source | vize lib pull composable:on-start-typing |
| Runtime exports | isTypingKeystroke, onStartTyping |
| Gzip budget | 1536 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 { isTypingKeystroke, onStartTyping } from "@vizejs/composable/on-start-typing";
Try it
Focus local guide search when typing begins
Redirect a printable key from a non-editable reading control into search while respecting native field editing and existing modifier shortcuts.
What to observe: Focus Reading control and press a letter: search receives actual focus and the shortcut delivery count increments. Then type to filter the local guides. Space activates the reading button normally, navigation keys do not redirect, and Ctrl/Meta/Alt shortcuts are ignored. Editing Workshop note does not focus search. Stop typing shortcut removes the redirect while both fields remain usable.
The default host is this preview's document. onStartTyping matches single printable characters other than space, with no Ctrl/Meta/Alt modifier and no editable element focused. The handler only counts and focuses the actual search input; v-model and the local computed filter own ordinary text editing. The document listener is passive, so the handler does not call preventDefault. The returned stop function permanently removes its watcher/listener; component scope disposal does the same. SSR has no document host and installs nothing. Search and note values are local and no request or save is sent. This is not a global shortcut on the parent documentation page.
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, ref, useId, useTemplateRef } from "vue";
import { onStartTyping } from "@vizejs/composable/on-start-typing";
const searchId = useId();
const search = useTemplateRef<HTMLInputElement>("search");
const query = ref("");
const note = ref("");
const deliveries = ref(0);
const readingActions = ref(0);
const stopped = ref(false);
const guides = ["Compiler guide", "Linter guide", "Keyboard guide"];
const matches = computed(() =>
guides.filter((guide) => guide.toLowerCase().includes(query.value.toLowerCase())),
);
const stop = onStartTyping(() => {
deliveries.value += 1;
search.value?.focus();
});
function stopShortcut(): void {
stop();
stopped.value = true;
}
</script>
<template>
<div class="composable-example">
<button type="button" @click="() => (readingActions += 1)">Reading control</button>
<p>Native reading activations: {{ readingActions }}</p>
<label :for="`${searchId}-query`">Search local guides</label>
<input :id="`${searchId}-query`" ref="search" v-model="query" type="search" />
<ul aria-label="Matching local guides">
<li v-for="guide in matches" :key="guide">{{ guide }}</li>
</ul>
<p v-if="matches.length === 0">No local guides match.</p>
<label :for="`${searchId}-note`">Workshop note</label>
<input :id="`${searchId}-note`" v-model="note" />
<button type="button" :disabled="stopped" @click="stopShortcut">Stop typing shortcut</button>
<output aria-live="polite"
>Typing shortcut deliveries: {{ deliveries }} · Active: {{ stopped ? "no" : "yes" }}</output
>
<p>
Focus Reading control and press a printable character to focus the search. Space, navigation
keys, and Ctrl/Meta/Alt shortcuts do not redirect focus. Editing either field stays ordinary
native typing. Stop removes the shortcut; the fields and local filtering remain usable. This
preview sends no search request or note save.
</p>
</div>
</template>
Runtime contract
| Utility | Category | Stability | SSR | Hydration | Cleanup | Targets | Host globals | Uses |
|---|---|---|---|---|---|---|---|---|
isTypingKeystroke |
input | experimental | safe | not-applicable | none | web, server, worker, native, desktop, terminal | — | — |
onStartTyping |
input | experimental | deterministic-fallback | stable | caller, reactive-scope | web, desktop | document |
isTypingKeystroke, tryOnScopeDispose |
API
isTypingKeystroke
Whether a keyboard event would type a printable character. Single-character keys (letters, digits, punctuation; not space) without ctrl/meta/alt qualify.
function isTypingKeystroke(event: KeyboardEvent): boolean
onStartTyping
Call a handler when the user starts typing while no editable element has focus — typically to focus a search field. Editable means input, textarea, select, or any element with isContentEditable, and elements with role="textbox"/"searchbox"/"combobox". Nothing is registered during server rendering; the listener is removed with the owning scope or the returned stop function.
function onStartTyping( handler: (event: KeyboardEvent) => void, options: OnStartTypingOptions = {}, ): () => void
Types
StartTypingHost
Document-like capability observed by onStartTyping.
| Member | Type | Description |
|---|---|---|
activeElement |
Element | null |
Currently focused element. |
OnStartTypingOptions
Options for onStartTyping.
| Member | Type | Description |
|---|---|---|
host? |
MaybeRefOrGetter<StartTypingHost | null | undefined> |
Reactive document capability for alternate runtimes and tests. |