Skip to content

Tags and entity search

This guide describes implemented 0.2 APIs. REQ: components-r-0014. REQ: components-r-0015. REQ: components-r-0016. REQ: components-r-0017. REQ: components-r-0018. REQ: components-r-0019. REQ: components-r-0021. REQ: components-r-0022. REQ: components-r-0023. REQ: components-r-0024.

The application supplies its own React renderer and a backend adapter. Import CSS once. Keep a controller stable for the mounted view; start/dispose are explicit host lifecycle actions. Do not create controllers as a side effect of every render or dispose them before unmounting controls.

import { createElement } from 'react';
import { createRoot } from 'react-dom/client';
import { createController, type SearchAdapter } from 'entity-viz-kit/core';
import { EntityVizProvider, EntitySearchControls } from 'entity-viz-kit/react';
import 'entity-viz-kit/styles.css';
export function mountSearch(container: HTMLElement, adapter: SearchAdapter) {
const controller = createController(adapter, { debounceMs: 180 });
const root = createRoot(container);
root.render(createElement(EntityVizProvider, { theme: 'light' },
createElement(EntitySearchControls, { controller })));
void controller.start();
return () => { root.unmount(); controller.dispose(); };
}

This is a browser mount helper, not an SSR rendering example. Library imports are SSR-safe, but the example renderer intentionally requires a DOM. A server host needs a request-scoped state/controller and a consistent initial snapshot for hydration; full server rendering was not run in the bootstrap environment.

The adapter receives opaque IDs, exact free text, contextual metadata, a request ID and a revision. It returns validated plain data. It owns endpoint credentials, authentication, query semantics and ranking; components never derive those from names. See the core guide for exact wire types. The source-backed search example supplies an explicitly synthetic adapter, not an implied production backend.

Use EntityQueryInput directly when an application owns state. Pass query, registry, optional presentation tagOrder, suggestions, and onAction. Apply its core actions with reduceState or your own compatible host store. Pass onCompositionChange into the request controller when using one; onSubmit dispatches the current intent. Only ephemeral popup/active-ID/focus state lives inside the input.

RecommendedEntities shares the same exact-ID onAdd and separate onInspect semantics. Supply a contextKey whenever the host context changes; this bounds retained focus state. sourceRevision/stale identify old recommendations. onFocusFallback restores focus to the query input when a context switch invalidates a focused recommendation.

QuerySummary displays explicit user query and host context separately. It exposes clear controls only for supplied capabilities. SearchStatus shows the real async phase, current revision and accepted data revision, including previous-result warnings and an explicit current-query retry.

useEntityController subscribes to a stable host controller using useSyncExternalStore. useRegistryRevision observes display metadata changes without changing query membership. No component creates localStorage, rewrites a URL, watches the clipboard, or automatically transmits page context.

ControlPrimary actionSecondary / keyboard behavior
Recommendation or suggestionAdd exact entity IDAlready-selected activation is idempotent and announced; inspection remains separate
Active QueryTagInspect when capability suppliedExplicit remove button, never click-to-toggle removal
Input Up / DownNavigate current suggestions by IDActive ID survives reorder; disappears rather than silently changing identity when removed
Input EnterAdd active suggestion, otherwise submitIME composition and its trailing Enter do not select or prematurely submit
Input Escape / TabClose suggestions / native next focusNeither clears the query
Empty-input BackspaceFocus last tag firstDelete/Backspace on focused tag removes it
Tag arrows / Home / EndNavigate tag controlsRTL direction is respected; Escape returns to text input
Remove or clearImmediate controlled actionFocus moves next, then previous, then input; no animation blocks retrieval

Suggestions are bounded (50 by default, configurable to the supported maximum) with visible truncation information. Recommendations are a separate surface rather than only a focused-input popup. If refresh removes the focused recommendation, it remains visibly labeled as belonging to an earlier set until blur. This preservation never crosses a context boundary. Existing labels/details remain data, not key identities.

Text insertion stays native plain text. An entity named in a pasted string does not become a tag without host-provided identity. There is no arbitrary contenteditable, hidden identity parser or drag-only control. Drag-and-drop is supplemental in the plan and is not shipped in this snapshot.

Typing updates visible state immediately; only request dispatch is debounced. Tags invalidate/supersede the pending text request immediately. A semantic revision covers exact text, membership and context, not visual tag order or inspection. Composition holds dispatch until the native committed value is applied. Ending a no-op composition does not repeat a search.

Initial/loading/refreshing/ready/empty/partial/failed/unavailable/disposed phases are distinct. The UI labels retained results and recommendations with their old revision. Those controls remain usable within the same context because their IDs still denote supplied entities; the old answer is not misrepresented as an answer to the new query. Context changes clear obsolete content synchronously in core. Retry uses current intent. Applications must still enforce authorization at their backend boundary.

Themes, scale, accessibility and customization

Section titled “Themes, scale, accessibility and customization”

EntityVizProvider accepts theme: light | dark | auto, density: comfortable | compact, mode: standard | compact | presentation, scale from 0.75 to 3, direction, locale, and strings. Separate providers support independent instances. Partial localized strings and function-valued plural/announcement strings merge with inherited defaults. Host entity labels and type names remain supplied data; use typeLabel for translated type labels.

Local renderGlyph and renderLabel hooks are functions in your application, never serialized adapter payloads. Escape/sanitize any custom content according to your own rendering boundary; built-in components use escaped text and original SVG glyphs. Unknown types have a visible fallback. Type, inclusion and inspection are indicated by more than color.

The stylesheet is scoped under .evk (the preserved native example uses .evk-app). Set custom properties on a provider’s style or a host-owned CSS class. Common tokens are --evk-bg, --evk-surface, --evk-text, --evk-muted, --evk-border, --evk-accent, --evk-accent-text, --evk-selected, --evk-selected-text, --evk-focus, --evk-warning, --evk-warning-bg, --evk-scale, and --evk-target. See the actual stylesheet for the complete token defaults; overrides must preserve contrast and interaction targets.

Tags wrap full labels. The query’s crowded tag region scrolls while its text input and clear/submit controls stay outside that scrolling list. Removal controls keep usable targets. Focus-visible, reduced motion and forced colors are styled. Compact/presentation modes use the same semantics, not separate state machines. Browser automation covers these behaviors under stated conditions; real assistive technology, physical software keyboards and user evaluation remain independent acceptance obligations.

The generated /react API lists every actual prop signature. The gallery shows controlled state, unknown/long labels, original glyphs, light/dark/RTL, metadata updates, delayed recommendation replacement and context-safe focus. No external backend is needed to run it. Example controls have real handlers; full rich result/evidence/profile widgets are assigned to 0.3 rather than represented by nonfunctional buttons.

The development runtime and local type facade have explicit limits: read ADR 0002. The packed ESM library leaves React external and does not include those bootstrap packages or types. Use authentic React and matching upstream declarations in a normal consumer; upstream-type validation and non-Chromium browser coverage remain pending in the current construction environment.