Deterministic ID Provider
Headless Deterministic ID Provider; covers React Aria SSRProvider, Vue useId.
| Package | @vizejs/ui/id |
| Maturity | stable |
| Own the source | vize lib pull id |
| Requires | context |
| Aliases | id provider, deterministic ids, hydration ids |
| Covers | React Aria SSRProvider, Vue useId |
Minimal setup
Use a Vue 3.5+ project with Vue SFC compilation configured (see Vite+ integration).
vp install @vizejs/ui
Add the public import below to <script setup lang="ts">. Components provide behavior without styles; the preview uses optional Paper styles.
import { IdProvider } from "@vizejs/ui/id";
Or copy the source into your project with vize lib pull id (see Source Distribution).
Try it
This is the basic example maintained with the component source, using the public package imports. The preview adds the optional Paper styles.
Open the interactive example · Styling these components
Copy the example
<!-- Hydration-stable IDs wiring a label and hint to an email field. -->
<script setup lang="ts">
import { computed } from "vue";
import { deriveDeterministicId, useDeterministicId } from "@vizejs/ui/id";
const inputId = useDeterministicId({ hint: "email" });
const hintId = computed(() => deriveDeterministicId(inputId.value, "hint"));
</script>
<template>
<div>
<label :for="inputId">Email address</label>
<input :id="inputId" type="email" autocomplete="email" :aria-describedby="hintId" />
<p :id="hintId">We only use this address for order receipts.</p>
</div>
</template>
API
IdProvider
Source: src/families/foundations/id/deterministic-id-provider.vue
Props
| Prop | Type | Default | Description |
|---|---|---|---|
prefix |
string |
The parent prefix when nested; otherwise "vize" |
Namespace prefix for this subtree. |
seed |
string | number |
Vue's SSR- and hydration-stable useId() value |
Stable request, island, or subtree seed. |
Slots
| Slot | Slot props | Description |
|---|---|---|
default |
{ readonly namespace: string; readonly prefix: string } |
Renders descendants with the resolved deterministic identifier namespace. |
Exposed
| Member | Type | Description |
|---|---|---|
namespace |
— | |
prefix |
— |
Behavior
Normative state × input → outcome table for
src/families/foundations/id/deterministic-id-provider.vue and @vizejs/ui/id.
Every row is proven by the named test in
src/families/foundations/id/id.test.ts; compile-only public type assertions
live in src/families/foundations/id/id.types.test-d.ts.
| # | State | Input | Outcome | Proven by |
|---|---|---|---|---|
| ID1 | root scope | explicit prefix and string seed | namespace is prefix-seed |
creates immutable request-local scopes with independent sequences |
| ID2 | root scope | repeated hint | monotonically increasing unique IDs | creates immutable request-local scopes with independent sequences |
| ID3 | root scope | child scope allocation | child and parent ID counters remain independent | creates immutable request-local scopes with independent sequences |
| ID4 | nested scope | duplicate child seeds | allocation index prevents collisions | keeps duplicate nested provider seeds collision-free |
| ID5 | nested scope | explicit prefix override | child prefix changes without losing parent namespace | supports a nested namespace prefix override |
| ID6 | any scope | unsafe prefix, seed, hint, or numeric seed | stable diagnostic rejects the value | rejects namespace values that are unsafe to compose |
| ID7 | consumer ID | valid punctuation or Unicode | exact consumer ID is accepted and branded | validates explicit IDs and derives semantic parts |
| ID8 | consumer ID | empty, whitespace, or ASCII control | stable diagnostic rejects the value | validates explicit IDs and derives semantic parts |
| ID9 | component setup | no provider | Vue useId() supplies a hydration-stable seed |
uses Vue's application ID sequence without a provider |
| ID10 | component setup | provider | nearest request-local scope allocates the ID | allocates descriptive IDs from the nearest provider |
| ID11 | component setup | reactive explicit ID appears | explicit ID replaces the generated fallback | preserves one fallback across reactive explicit ID changes |
| ID12 | component setup | reactive explicit ID disappears | original generated fallback is restored without renumbering | preserves one fallback across reactive explicit ID changes |
| ID13 | outside setup | call composable | stable setup diagnostic is thrown | rejects composable use outside component setup |
| ID14 | provider slot | render | slot receives validated namespace and prefix | exposes the resolved namespace to its slot and public instance |
| ID15 | nested providers | mount | parent and nested consumer IDs are unique | keeps duplicate nested provider seeds collision-free |
| ID16 | SSR request | repeat identical tree and seed | byte-identical IDs are rendered | renders byte-stable IDs for repeated and concurrent SSR requests |
| ID17 | concurrent SSR | different request seeds | request-local sequences never bleed across renders | renders byte-stable IDs for repeated and concurrent SSR requests |
| ID18 | SSR followed by hydration | identical provider tree | client retains server IDs without mismatch diagnostics | hydrates provider IDs without warnings or replacement |
| ID19 | nested provider insertion | sibling control allocation | child-scope counter cannot renumber sibling IDs | keeps ID and child-scope allocation sequences independent |
| ID20 | public types | invalid seed, hint, prefix, or unbranded ID assignment | TypeScript rejects closed-contract misuse | src/families/foundations/id/id.types.test-d.ts |
Assistive-technology notes
The primitive only produces IDs; components remain responsible for assigning
them to correct relationships such as for, aria-labelledby,
aria-describedby, aria-controls, and aria-errormessage. Stable IDs avoid
relationship loss during hydration, but do not make an invalid relationship
accessible.
Escape hatches and constraints
- Pass an explicit
idwhen an external document contract owns the value. - Give separate SSR islands distinct provider seeds, or configure Vue's
application
idPrefix, when their DOM is combined into one document. - Allocate generated IDs during setup. Calling a scope's
nextId()from a render loop intentionally changes the sequence and is unsupported. - User-owned IDs allow Unicode and punctuation. Escape them before using them in a CSS selector.