Skip to content

解决 Shadcn Sheet 组件报错 "DialogContent requires a DialogTitle"

问题描述

使用 Shadcn UI 的 Sheet 组件时,控制台报错:

DialogContent requires a DialogTitle for the component to be accessible for screen reader users

此错误提示的核心问题是 可访问性缺失:Shadcn 的 Sheet 组件需要提供标题元素来保障屏幕阅读器用户的可访问性。

虽然开发者并未直接使用 Dialog 组件,但 Sheet 组件实际上是继承自 Dialog 组件。因此,SheetContent 需要配合 SheetTitle 使用,才能满足 ARIA 可访问性规范的要求。

典型的错误使用案例如下:

jsx
<SheetContent side="right" className="fixed z-50">
  <div>
    <p>Sheet Content</p>
  </div>
</SheetContent>

解决方案

添加 SheetTitle 组件

SheetContent 内部添加 SheetTitle 作为其直接子元素:

jsx
<SheetContent side="right">
  <SheetTitle>菜单标题</SheetTitle> {/* 添加标题 */}
  <div>
    {/* 内容区域 */}
  </div>
</SheetContent>

注意事项

  • SheetTitle 必须是 SheetContent 的直接子元素
  • 标题文本应清晰描述弹窗内容,如 "菜单选项"、"用户设置"

隐藏视觉显示(保留屏幕阅读器可访问性)

若不想展示标题文本(如不希望改变现有UI布局),使用 sr-only 类实现视觉隐藏:

jsx
<SheetTitle className="sr-only">
  菜单标题 (仅供屏幕阅读器使用)
</SheetTitle>

sr-only 的 CSS 实现(Tailwind 内置)

Tailwind CSS 已提供内置 sr-only 类:

css
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

错误做法

避免使用 display: none 或其 Tailwind 等价类 hidden

jsx
{/* 错误示例 - 完全移除可访问性 */}
<SheetTitle className="hidden">标题</SheetTitle>
解决方案视觉效果屏幕阅读器支持
sr-only隐藏✅ 支持
display: none隐藏❌ 不支持

完整解决方案代码

结合 Shadcn Sheet 组件的正确实现方式:

jsx
<Sheet open={openMenu} onOpenChange={setOpenMenu}>
  <SheetTrigger asChild>
    <Button variant="ghost">
      <MenuIcon color={location.pathname === "/" ? "white" : "black"} size="2em" />
    </Button>
  </SheetTrigger>
  
  <SheetContent side="right" className="fixed z-50">
    {/* 隐藏的标题 (仅屏幕阅读器可见) */}
    <SheetTitle className="sr-only">主菜单</SheetTitle>
    
    {/* 内容区域 */}
    <div>
      <p>菜单选项内容</p>
    </div>
  </SheetContent>
</Sheet>

技术原理

为何需要添加 Title?

  • ARIA 规范:对话框(包括 Sheet)必须包含可访问的名称(通过 aria-labelledby 实现)
  • 组件继承:Shadcn 的 Sheet 是基于 Dialog 构建的,继承其可访问性约束
  • 屏幕阅读器支持:缺少标题元素会导致:
    • 屏幕阅读器用户无法获取对话框目的
    • 违反 WCAG 可访问性标准

sr-only 的工作原理

该方法在保留可访问性的同时:

  1. 元素保持在 DOM 中 → 能被屏幕阅读器检测
  2. 通过绝对定位和裁剪 → 在视觉上不占据空间
  3. 不干扰页面布局 → UI 效果保持不变

最佳实践

  1. 优先使用文本标题:默认显示标题更能提升整体可访问性
  2. 语义化命名:标题应准确描述内容(如 "用户设置" 优于"弹窗")
  3. 测试验证:使用 NVDA, VoiceOver 或 Chrome DevTools 审查模式验证可访问性

遵循上述方案可解决 Console 错误提示,同时确保组件合规支持无障碍访问要求。