docs
Getting Started
Tutorials
How-To Guides
Explanation
Reference
Help
Getting Started
Tutorials
How-To Guides
Explanation
Reference
Help

Accessibility

Needle Engine includes built-in accessibility support, making interactive 3D content discoverable and usable with screen readers and other assistive technology — without requiring any code changes for common use cases.

Since v4.15.0, Needle Engine automatically maintains a visually-hidden DOM overlay that mirrors your 3D scene's interactive elements with proper ARIA roles and labels. When users hover over interactive objects, the browser's live region announces them — no focus steal required.

How It Works

The AccessibilityManager creates an invisible DOM tree alongside your 3D canvas. This tree mirrors interactive objects in the scene with proper ARIA semantics, so assistive technology (like screen readers) can discover and navigate them.

  • ARIA roles and labels — each interactive object gets a role and aria-label in the hidden DOM
  • Live region — hovering over 3D objects announces them to the screen reader via aria-live="polite" without moving focus
  • Focus API — focus() and unfocus() let you route keyboard focus to a hidden DOM element when a 3D object is activated
  • No visual change — the overlay is position: absolute; width: 1px; height: 1px; clip: rect(0,0,0,0), completely invisible

Automatic Integration

The following built-in components register themselves with the AccessibilityManager automatically — no configuration needed:

ComponentARIA roleLabel announced
Buttonbutton"<ObjectName> button"
TexttextText content
DragControlsbutton"Drag <ObjectName>"
ChangeTransformOnClickbutton"Move <object> to <target> on click"
ChangeMaterialOnClickbutton"Change material to <material>"
EmphasizeOnClickbutton"Emphasize <target> on click"
PlayAudioOnClickbutton"Play audio: <clip>"
PlayAnimationOnClickbutton"Plays animation <name> on <target>"

If your scene uses any of these components, screen readers can already announce and navigate interactive elements out of the box.

Accessing the Manager

From any component, access the manager via this.context.accessibility:

import { Behaviour } from "@needle-tools/engine";

export class MyInteractiveObject extends Behaviour {
    onEnable() {
        // Register this object as an accessible button
        this.context.accessibility.updateElement(this.gameObject, {
            role: "button",
            label: "Spin the cube",
        });
    }

    onDisable() {
        this.context.accessibility.removeElement(this.gameObject);
    }
}

Custom Component Example

Here is a complete example of a custom interactive component that participates in the accessibility tree:

import { Behaviour, IPointerEventHandler, PointerEventData, serializable } from "@needle-tools/engine";

export class AccessiblePortal extends Behaviour implements IPointerEventHandler {

    /** Label read by screen readers */
    @serializable()
    label: string = "Enter portal";

    onEnable() {
        this.context.accessibility.updateElement(this.gameObject, {
            role: "button",
            label: this.label,
        });
    }

    onDisable() {
        this.context.accessibility.removeElement(this.gameObject);
    }

    onPointerEnter(_data: PointerEventData) {
        this.context.accessibility.hover(this.gameObject);
    }

    onPointerClick(_data: PointerEventData) {
        // ... do the portal logic
    }
}

ARIA Roles Reference

Common ARIA roles for 3D interactive objects:

RoleWhen to use
buttonClickable objects that trigger an action
imgDecorative or informational 3D models
regionA major section of the scene
applicationComplex interactive widgets (drag, multi-step)
statusObjects whose state changes and should be announced

For a complete list, see the WAI-ARIA roles reference.

Tips & Best Practices

Label interactive objects clearly

Use descriptive, action-oriented labels: "Rotate left" is better than "Object 3". The label is what a screen reader user hears when they encounter the element.

Use hover() for cursor interaction

When a user moves the cursor over an interactive 3D object, call accessibility.hover(obj) to announce it. The live region announces without stealing focus — safe to call frequently.

Clean up on disable

Always call removeElement() in onDisable() or onDestroy(). Orphaned elements stay in the accessibility tree after the 3D object is gone.

Available since v4.15.0

The AccessibilityManager was introduced in Needle Engine v4.15.0 (February 2026). If you are on an older version, upgrade to access these features.

Suggest changes
Last Updated: 3/5/26, 10:23 AM

Extras

ChatGPT Ask ChatGPT Claude Ask Claude
Copy Markdown

Navigation

  • Getting Started
  • Tutorials
  • How-To Guides
  • Explanation
  • Reference
  • Help

Extras

ChatGPT Ask ChatGPT Claude Ask Claude
Copy Markdown