发现于 #3787 的浏览器实证(PR:claude/issue-3786-3787-pageheader-docs-demo),不在该 PR 处理 —— 那一单改的是一份 demo JSON,这一条是索引页的 DOM 结构问题,与哪个示例无关。先说清:不是 #3787 引入的 —— 换 demo 之前之后都在报,且打到 85 个示例。
现象
/docs/guide/schema-catalog 上,SchemaCatalogIndex.tsx:111 把每个卡片渲染成 button,卡片里嵌的是 SchemaThumbnail(:116),而 SchemaThumbnail 会用真的 SchemaRenderer 渲染示例本身。任何含按钮节点的示例于是落成 button 套 button。
Chromium 控制台(headless、Next dev、访问该页)读数:
In HTML, %s cannot be a descendant of <%s>.
This will cause a hydration error.%s button <button>
| <%s> cannot contain a nested %s.
See this log for the ancestor stack trace. button <button>
命中面:grep -rl '"type": "button"' examples/schema-catalog/src/schemas | wc -l = 85 个示例。
为什么值得记一笔
React 明确把这个归为 hydration error 而不是样式瑕疵:嵌套按钮的 HTML 会被浏览器解析器重构(内层按钮被提到外层之外),server HTML 与 client 树因此不一致。此外它本身就是可访问性缺陷 —— 交互控件套交互控件,键盘与读屏行为不确定。
建议处置
把卡片外壳从 button 换成 div + role="button" 之外的方案更稳:推荐外壳用非交互元素,点击目标做成覆盖层(一个绝对定位的 button 兄弟节点,aria-label 给示例名),缩略图内容 pointer-events: none。这样卡片可点、示例内部的按钮不再被嵌套。SchemaThumbnail 已经是「scaled, non-interactive preview」,pointer-events: none 与它的定位一致。
参考位置
apps/site/app/components/SchemaCatalogIndex.tsx:111(卡片外壳 button)、:116(嵌入 SchemaThumbnail)
apps/site/app/components/SchemaThumbnail.tsx:60-128(内部真实 SchemaRenderer)
content/docs/guide/schema-catalog.mdx:33(索引页入口)
关联:#3787(发现于此)
发现于 #3787 的浏览器实证(PR:
claude/issue-3786-3787-pageheader-docs-demo),不在该 PR 处理 —— 那一单改的是一份 demo JSON,这一条是索引页的 DOM 结构问题,与哪个示例无关。先说清:不是 #3787 引入的 —— 换 demo 之前之后都在报,且打到 85 个示例。现象
/docs/guide/schema-catalog上,SchemaCatalogIndex.tsx:111把每个卡片渲染成button,卡片里嵌的是SchemaThumbnail(:116),而SchemaThumbnail会用真的SchemaRenderer渲染示例本身。任何含按钮节点的示例于是落成 button 套 button。Chromium 控制台(headless、Next dev、访问该页)读数:
命中面:
grep -rl '"type": "button"' examples/schema-catalog/src/schemas | wc -l= 85 个示例。为什么值得记一笔
React 明确把这个归为 hydration error 而不是样式瑕疵:嵌套按钮的 HTML 会被浏览器解析器重构(内层按钮被提到外层之外),server HTML 与 client 树因此不一致。此外它本身就是可访问性缺陷 —— 交互控件套交互控件,键盘与读屏行为不确定。
建议处置
把卡片外壳从
button换成div+role="button"之外的方案更稳:推荐外壳用非交互元素,点击目标做成覆盖层(一个绝对定位的button兄弟节点,aria-label给示例名),缩略图内容pointer-events: none。这样卡片可点、示例内部的按钮不再被嵌套。SchemaThumbnail已经是「scaled, non-interactive preview」,pointer-events: none与它的定位一致。参考位置
apps/site/app/components/SchemaCatalogIndex.tsx:111(卡片外壳button)、:116(嵌入SchemaThumbnail)apps/site/app/components/SchemaThumbnail.tsx:60-128(内部真实SchemaRenderer)content/docs/guide/schema-catalog.mdx:33(索引页入口)关联:#3787(发现于此)