embed-semantic-navigator

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Embed Semantic Navigator

嵌入语义导航面板

Choose the package

选择合适的包

StackPackage
React
@real-a11y-dev/react
Any other / vanilla
@real-a11y-dev/inspector
Install as a devDependency. Do not ship the panel to end users.
技术栈包名
React
@real-a11y-dev/react
其他/原生JS
@real-a11y-dev/inspector
将其安装为devDependency。不要将该面板交付给终端用户。

Keep it out of production

确保不进入生产环境

A top-level static import is not tree-shaken away by wrapping
if (import.meta.env.DEV)
. Lazy-import the panel (dynamic
import()
) behind a DEV / explicit flag so production builds drop it.
通过
if (import.meta.env.DEV)
包裹的顶层静态导入无法被 tree-shaking 移除。延迟导入该面板(使用动态
import()
),并置于DEV环境或显式标志之后,这样生产构建时就会剔除它。

React

React 场景

tsx
import { lazy, Suspense, useRef } from "react";

const SemanticNavigator = lazy(() =>
  import("@real-a11y-dev/react").then((m) => ({
    default: m.SemanticNavigator,
  })),
);

export function DevAuditOverlay({ children }: { children: React.ReactNode }) {
  // Vite: `import.meta.env.DEV`. Webpack/Next: `process.env.NODE_ENV !== "production"`.
  if (!import.meta.env.DEV) return <>{children}</>;

  const rootRef = useRef<HTMLDivElement>(null);

  return (
    <div ref={rootRef}>
      {children}
      <Suspense fallback={null}>
        <SemanticNavigator root={rootRef} mode="a11y" floating />
      </Suspense>
    </div>
  );
}
root
is required and must point at the audited subtree — a ref that is never attached to a DOM node leaves the panel empty. Wrap the app (or pass the same ref you already hang on
<main>
).
Use as
<DevAuditOverlay><App /></DevAuditOverlay>
.
Also available:
useSemanticTree
,
useActiveModal
. Prefer floating props for overlays; inline layout for split-pane debugging.
Next.js App Router: client-only mount; verify production build has no
window is not defined
/ hydration errors (SSR risk is invisible in a Vite SPA). Recipe: https://real-a11y.dev/recipes/nextjs
tsx
import { lazy, Suspense, useRef } from "react";

const SemanticNavigator = lazy(() =>
  import("@real-a11y-dev/react").then((m) => ({
    default: m.SemanticNavigator,
  })),
);

export function DevAuditOverlay({ children }: { children: React.ReactNode }) {
  // Vite: `import.meta.env.DEV`. Webpack/Next: `process.env.NODE_ENV !== "production"`.
  if (!import.meta.env.DEV) return <>{children}</>;

  const rootRef = useRef<HTMLDivElement>(null);

  return (
    <div ref={rootRef}>
      {children}
      <Suspense fallback={null}>
        <SemanticNavigator root={rootRef} mode="a11y" floating />
      </Suspense>
    </div>
  );
}
root
为必填项,必须指向要审计的子树——若引用未关联到DOM节点,面板将显示为空。包裹整个应用(或传递已挂载在
<main>
上的相同引用)。
使用方式:
<DevAuditOverlay><App /></DevAuditOverlay>
同时提供以下API:
useSemanticTree
useActiveModal
。对于覆盖层场景,优先使用浮动属性;分栏调试时使用内联布局。
Next.js App Router:仅在客户端挂载;需验证生产构建中不存在
window is not defined
或 hydration 错误(在Vite单页应用中SSR风险不可见)。相关方案:https://real-a11y.dev/recipes/nextjs

Vanilla / any framework

原生JS/任意框架场景

ts
import { createInspector } from "@real-a11y-dev/inspector";

const inspector = createInspector({
  root: document.getElementById("app"),
  container: document.getElementById("tree-panel"),
  viewMode: "a11y", // "dom" | "a11y" | "tab"
  theme: "auto",
});
inspector.mount();
// inspector.setRoot / setViewMode / refresh / getTree
Prefer
mount: "shadow"
when available. Host side-effects (
highlightOnHover
, etc.) stay opt-in.
ts
import { createInspector } from "@real-a11y-dev/inspector";

const inspector = createInspector({
  root: document.getElementById("app"),
  container: document.getElementById("tree-panel"),
  viewMode: "a11y", // "dom" | "a11y" | "tab"
  theme: "auto",
});
inspector.mount();
// inspector.setRoot / setViewMode / refresh / getTree
若支持,优先使用
mount: "shadow"
。宿主端副作用(如
highlightOnHover
等)保持可选启用。

Related

相关资源

  • Storybook →
    a11y-in-storybook
  • Assert on trees in tests →
    a11y-snapshot-tests
  • Storybook →
    a11y-in-storybook
  • 在测试中断言树结构 →
    a11y-snapshot-tests