API reference
Look up component props, hook options and their defaults. Start with Lighting and Lighting.Surface; use the hooks when you need to connect an existing host.
Lighting
Wrap the part of your interface that should share a light. Lighting adds no DOM element. Each surface uses its nearest owner, so nested owners create independent lights.
<Lighting motion="system" radius={480} intensity={0.75}> {/* Your surfaces */}</Lighting>| Prop / option | Type | Default | Description |
|---|---|---|---|
motion | 'system' | 'dynamic' | 'static' | 'system' | System respects reduced-motion and device preferences. Dynamic follows mouse or pen input, even with reduced motion enabled. Static keeps a fixed direction. Touch does not drive the light. |
staticDirection | number | 'random' | 315 | Direction in degrees for fixed lighting. Random chooses one shared direction per mount and keeps it across ordinary rerenders. Numbers must be finite. |
radius | number | 480 | Distance over which dynamic lighting fades outside a surface, in viewport CSS pixels. Must be positive and finite. |
intensity | number | 0.75 | Shared light strength. Must be finite and between 0 and 1; invalid values throw a RangeError. |
children | ReactNode | Required | The area that shares this light. Ordinary children stay unchanged; only explicit surfaces respond. |
ref | Ref<Light> | Unset | Optional stable light handle. Call its refresh() method after position-only layout changes. |
Pointer input comes from the document. The scope chooses which surfaces respond; it does not clip input to a wrapper rectangle. staticDirection applies whenever fixed lighting is active, including when motion="system" respects reduced motion.
Lighting.Surface
Mark an element that should respond to its nearest light. It renders one HTML host and preserves your native attributes and event handlers.
<Lighting.Surface as="article" edgeStyle="raised"> Your content</Lighting.Surface>| Prop / option | Type | Default | Description |
|---|---|---|---|
pseudoElement | 'after' | 'before' | 'after' | Decoration slot. Choose before to preserve an existing ::after. If both slots are occupied, or the host is a native input, use a wrapper. Invalid values throw a RangeError. |
edgeStyle | 'raised' | 'recessed' | 'matte' | 'raised' | How the edge responds to light. All three styles preserve your component appearance. |
color | string | currentColor | Highlight color. Follows the host text color by default. Accepts any CSS color string, including a CSS variable. |
shadowColor | string | #0008 | Color on the opposite edge. Accepts any CSS color string; use transparent to remove this shadow on a light surface. |
borderWidth | number | 1 | Decorative edge thickness in pixels; it does not change the host border. Negative values clamp to 0. Non-finite values use the default. |
intensity | number | 1 | Multiplier for the shared light strength. Finite values clamp to 0–1; non-finite values use the default. |
as | HTML tag name | 'div' | The HTML element to render. Native attributes and the ref follow the chosen tag; custom React components are not accepted here. |
children | ReactNode | Unset | Content rendered inside the host. Use a wrapper for inputs and other elements that cannot display the decoration themselves. |
ref | Ref<HTMLElement for the chosen tag> | Unset | Forwarded to the rendered element alongside the internal registration ref. React 19 callback-ref cleanup is preserved. |
className | string | Unset | Your classes, combined with the decoration classes. |
style | CSSProperties | Unset | Your inline styles, merged after the decoration bindings. Keep Edge-owned CSS variables intact unless deliberately overriding them. |
Place every Lighting.Surface inside a Lighting owner; rendering it outside one throws an error. For native inputs and occupied pseudo-elements, see Integration.
Existing host borders are measured so the decoration aligns with their outside edge. borderWidth changes the decoration thickness, not the host border. For a custom component that already exposes its host, use useSurface below.
useLight(options?)
Create a light when you need to connect existing components through hooks. The returned Light handle stays stable; changing options updates the existing light.
function useLight(options?: LightOptions): Light;| Prop / option | Type | Default | Description |
|---|---|---|---|
motion | 'system' | 'dynamic' | 'static' | 'system' | System respects reduced-motion and device preferences. Dynamic follows mouse or pen input, even with reduced motion enabled. Static keeps a fixed direction. Touch does not drive the light. |
staticDirection | number | 'random' | 315 | Direction in degrees for fixed lighting. Random chooses one shared direction per mount and keeps it across ordinary rerenders. Numbers must be finite. |
radius | number | 480 | Distance over which dynamic lighting fades outside a surface, in viewport CSS pixels. Must be positive and finite. |
intensity | number | 0.75 | Shared light strength. Must be finite and between 0 and 1; invalid values throw a RangeError. |
Omitted options use their defaults. radius controls distance attenuation for dynamic lighting. Fixed lighting uses staticDirection and does not fade because an element is far from an arbitrary origin.
light.refresh()
Call light.refresh() after your application moves an element or changes its host border thickness without a size notification. It remeasures geometry on the next frame, including while the pointer is stationary.
interface Light { refresh(): void;}Call it after React commits the new layout. It schedules an update without replacing the light handle or requiring pointer movement.
useSurface(light, options?)
Connect one existing HTML host to a light. Attach the returned ref. Edge applies and removes its own decoration; keep your existing className and style props.
const ref = useSurface<HTMLElement>(light, options);function Area() { const light = useLight(); return <><ExistingCard light={light} /><ExistingCard light={light} /></>;}
function ExistingCard({ light }: { light: Light }) { const ref = useSurface<HTMLDivElement>(light); return <Card ref={ref}>Your existing component</Card>;}| Prop / option | Type | Default | Description |
|---|---|---|---|
pseudoElement | 'after' | 'before' | 'after' | Decoration slot. Choose before to preserve an existing ::after. If both slots are occupied, or the host is a native input, use a wrapper. Invalid values throw a RangeError. |
edgeStyle | 'raised' | 'recessed' | 'matte' | 'raised' | How the edge responds to light. All three styles preserve your component appearance. |
color | string | currentColor | Highlight color. Follows the host text color by default. Accepts any CSS color string, including a CSS variable. |
shadowColor | string | #0008 | Color on the opposite edge. Accepts any CSS color string; use transparent to remove this shadow on a light surface. |
borderWidth | number | 1 | Decorative edge thickness in pixels; it does not change the host border. Negative values clamp to 0. Non-finite values use the default. |
intensity | number | 1 | Multiplier for the shared light strength. Finite values clamp to 0–1; non-finite values use the default. |
An element can belong to only one light controller. Connect the returned ref to the element that actually displays the border, not to a parent whose dimensions differ.
edgeStyle changes update the existing registration. Appearance options update without replacing the host. Hook decoration is attached on the client; its server markup contains only your own styles. Use Lighting.Surface when you need the decorative CSS in server output too.
Rendering and cleanup
Hooks can create handles and render markup on the server without accessing the DOM. Client effects activate the light after hydration. Cleanup restores controller-owned inline variables, removes browser subscriptions and cancels pending frames. Setup can restart during React StrictMode checks.
The React adapter requires React 19. Tests cover React’s server renderer and hydration APIs; they do not establish integration with every SSR framework.