App setup

Inspector

X-ray for a page built with Ouro HX: outlines every Ouro component on the page with its name, linked to its docs, and lists them all for keyboard and screen reader users. Each tag names the component's registry item; the bar at the bottom opens the list (a Sheet), every component in document order with its "Docs" and, from sourceHref, "Source" links. Outlines follow their components through scrolling, resizing, overlays and changes to the page, measured once a frame at most; they never take a pointer, so the page stays usable underneath, and only the tags do. X-ray shows only what a person can see and reach: an outline is cut to the part a scrolling box lets show, a tag hides while a menu or a list lies over it, the page behind an open modal dialog is left alone, and a part (a Radio) counts with its component (its RadioGroup). X-ray never draws over the page's text: an outline's edge breaks where a line of text crosses it, and a tag sits where it covers no text and no other tag, or hides. Its bar is a landmark named by label. Escape or Close turns it off, once Escape has closed any other overlay. It renders nothing on the server.

Outline every Ouro component on this page.

In Spoonjoy

Spoonjoy, a recipe app, is built with Ouro HX (how).

In its source: app/routes/test-kitchen.tsx

Install

Once per app, with Tailwind CSS v4 and an @/* path alias (Ouro HX is built on Base UI, so --base base; skip -t in an existing app):

npx shadcn@latest init --base base --preset nova --yes --no-monorepo
npx shadcn@latest add ourostack/ouro-ui/ouro-base#v1.2.13

Then the component. From v0.8.0 it installs only the helpers it imports and never touches your stylesheet (Installing):

npx shadcn@latest add ourostack/ouro-ui/inspector#v1.2.13

Or, with the @ouro namespace set up:

npx shadcn@latest add @ouro/ouro-base @ouro/inspector

Its tests, stories and Playwright spec are optional. They need Vitest 4.1.11 or later, and from v0.8.0 never change a version your app has (Testing):

npx shadcn@latest add ourostack/ouro-ui/inspector#v1.2.13 ourostack/ouro-ui/inspector-tests#v1.2.13
import { Inspector } from "@/components/ouro/inspector/inspector";

Paths use shadcn's default @/ alias; the CLI rewrites them to yours.

Example

const [xray, setXray] = useState(false);
<Switch label="X-ray" checked={xray} onCheckedChange={setXray} />
<Inspector open={xray} onOpenChange={setXray} />
<Inspector open={xray} onOpenChange={setXray} sourceHref={(item) => sourceOf(item)} />

Use instead when

  • Use your browser's developer tools instead when you need more than which component is where; the data-ouro, data-ouro-control and data-ouro-part attributes X-ray reads are there too.

Props

Type: InspectorProps.

docsHref
Type: ((item: string) => string)
The address of an item's docs page, from its registry name, where each tag and the list link. Without it they link to Ouro's public docs, https://ui.ouro.bot/docs/<item>/.
label
Type: string
Default: "X-ray"
What X-ray is called, on its bar and as its list's title. Translate it here.
onOpenChange (required)
Type: (open: boolean) => void
Called with false when the person closes X-ray (its Close button, or Escape).
open (required)
Type: boolean
Whether X-ray is on: outlines over every Ouro component, and the bar with the list. Pair it with onOpenChange.
sourceHref
Type: ((item: string, element: Element) => string | undefined)
The address of the source that renders a component, if you publish it: the list shows a Source link where this returns one.

Don't use

These are not props. Passing one fails the type check with the fix in the error, and in development a console message names the fix.

  • isOpen: Not a prop. Ouro UI uses open with onOpenChange: <Inspector open={xray} onOpenChange={setXray}>.
  • onClose: Not a prop. onOpenChange gets false when X-ray closes: onOpenChange={setXray}.