React API
Import the adapter and its types from the dedicated React entry:
import { Orbz, type OrbzProps } from "@neongate-ai/orbz/react";OrbzProps is an alias of OrbzOptions: base visual options combined with a
mutually exclusive preset-or-custom-colors union.
Props
| Prop | Type | Default | Native output |
|---|---|---|---|
state | OrbzState | "idle" | state |
size | number | string | "16rem" | size; numbers become pixels |
speed | number | 1 | speed |
paused | boolean | false | Boolean paused attribute |
elevated | boolean | false | Boolean elevated attribute |
reducedMotion | OrbzReducedMotion | "system" | reduced-motion |
preset | OrbzPresetName | NeonGate colors | preset |
colorPrimary | string | NeonGate primary | color-primary |
colorSecondary | string | NeonGate secondary | color-secondary |
colorAccent | string | NeonGate accent | color-accent |
colorHighlight | string | NeonGate highlight | color-highlight |
colorBackground | string | NeonGate core | color-background |
Optional color strings are trimmed. Empty color strings are omitted.
Preset mode
import { Orbz } from "@neongate-ai/orbz/react";
export function SpeakingOrb() {
return (
<Orbz
state="idle"
preset="magenta"
size={320}
speed={1.1}
elevated
/>
);
}With preset present, TypeScript rejects all five custom color props.
Custom palette mode
import { Orbz, type OrbzProps } from "@neongate-ai/orbz/react";
const appearance = {
colorPrimary: "#7C3AED",
colorSecondary: "#22D3EE",
colorAccent: "#F472B6",
colorHighlight: "#FDE68A",
colorBackground: "#09090B",
} satisfies OrbzProps;
export function BrandedOrb() {
return <Orbz state="idle" size="18rem" {...appearance} />;
}With any custom color present, TypeScript rejects preset. Missing custom
colors fall back to the default NeonGate values.
The native element remains defensive when JavaScript data bypasses the type union: an explicit preset wins over custom colors and the component logs a conflict error.
State-driven component
import { Orbz, type OrbzState } from "@neongate-ai/orbz/react";
interface VoiceIndicatorProps {
state: OrbzState;
paused?: boolean;
}
export function VoiceIndicator({ state, paused = false }: VoiceIndicatorProps) {
return (
<div role="status" aria-live="polite">
<Orbz
state={state}
paused={paused}
preset="neongate"
reducedMotion="system"
elevated
/>
<span>Assistant is {state}</span>
</div>
);
}Render accessible status semantics in the surrounding React tree. Orbz is a visual expression; it should not be the only representation of state.
Strict surface
The adapter intentionally does not extend HTMLAttributes<HTMLElement>. These
are not accepted public props:
// Not part of OrbzProps:
// <Orbz className="..." />
// <Orbz style={{ ... }} />
// <Orbz ref={...} />
// <Orbz>children</Orbz>The boundary keeps Orbz appearance controlled by documented attributes and prevents consumers from depending on host styling or internal implementation details. Use a wrapper element for layout, semantics, labels, and event-driven application UI.
Because no ref is exposed, native playback methods are not available through
the adapter. Express playback declaratively with the paused prop and change
state to rebuild the visual state.
Boolean output
The adapter emits a native boolean attribute only when its prop is true:
<Orbz paused={false} elevated={true} />This renders without paused and with elevated. It avoids the native HTML
pitfall where paused="false" is still truthy because the attribute is present.
Next.js boundary
Use the adapter inside a Client Component when local state or event handlers drive it:
"use client";
import { Orbz } from "@neongate-ai/orbz/react";
export function OrbClient() {
return <Orbz state="idle" preset="neongate" />;
}The package is safe during server evaluation: element class creation is
deferred until HTMLElement exists, and registration happens after the React
adapter mounts. Keep the initial server and client props identical to avoid a
hydration mismatch.
See the React example and Next.js example for complete applications.