You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用react-bootstrap Accordion实现表格行展开时的DOM嵌套警告求助

解决React Bootstrap Accordion表格行展开的DOM嵌套警告

方案一:重构Accordion结构适配表格规范

核心是调整Accordion组件的渲染层级,让它生成的DOM不再嵌套在<tr>内部,完全符合HTML表格的结构要求。

修改后的代码示例:

<div className="row me-2 ms-2">
  <table className="table accordian-table table header-fixed border mt-2">
    <thead>
      <tr>
        <th width="30%" className="text-center">Col 1</th>
        <th width="30%" className="text-center">Col 2</th>
        <th width="30%" className="text-center">Col 3</th>
        <th width="25px" className="float end"></th>
      </tr>
    </thead>
    <tbody className="scroll">
      <Accordion activeKey={activeAccordionKey} onSelect={(selectedKey) => setActiveAccordionKey(selectedKey)} flush>
        {items?.length ? (
          [...items].map((item, index) => (
            <Accordion.Item key={index} eventKey={index}>
              {/* 主数据行:将Accordion.Header渲染为tr */}
              <Accordion.Header as="tr" onClick={() => getFlows(item)} className="main-table-content">
                <td width="30%" title={item.prop1} className="text-center pt-2">
                  {item.prop1}
                </td>
                <td width="30%" title={item.prop2} className="text-center pt-2">
                  {item.onboardingInfo.prop2}
                </td>
                <td width="30%" title={item.prop3} className="text-center pt-2">
                  {item.onboardingInfo.prop3}
                </td>
                <td width="25px">{" "}</td>
              </Accordion.Header>
              {/* 展开内容行:将Accordion.Body渲染为tr,内部td跨所有列 */}
              <Accordion.Body as="tr">
                <td colSpan="4" onClick={(e) => e.stopPropagation()}>
                  <table className="table">
                    <thead>
                      <tr>
                        <th>Flow Name</th>
                        <th>Flow Type</th>
                        <th>Dnid</th>
                        <th>Ext</th>
                        <th>Created By</th>
                        <th>Created On</th>
                      </tr>
                    </thead>
                    <tbody>
                      {selectedItem?.length ? (
                        [...selectedItem.values()].map((slItem) => (
                          <tr key={slItem.flowName}>
                            <td>{slItem.flowName}</td>
                            <td>{slItem.flowTypeId}</td>
                            <td>{slItem.dnid}</td>
                            <td>{slItem.createdBy}</td>
                            <td>{slItem.createdOn}</td>
                          </tr>
                        ))
                      ) : (
                        <tr>
                          <td>No Configs Available</td>
                        </tr>
                      )}
                    </tbody>
                  </table>
                </td>
              </Accordion.Body>
            </Accordion.Item>
          ))
        ) : (
          <tr>
            <td colSpan="4">No ItemsFound</td>
          </tr>
        )}
      </Accordion>
    </tbody>
  </table>
</div>

关键修改点:

  • 将<Accordion.Item>直接作为<tbody>的子元素,不再嵌套在<tr>内部
  • 通过as="tr"属性,让<Accordion.Header>和<Accordion.Body>渲染为表格行元素,而非默认的<div>
  • 展开内容使用colSpan="4"的<td>包裹子表格,保证表格结构合法

方案二:手动实现展开逻辑(完全自定义DOM)

如果不想依赖Accordion组件的默认渲染,可以直接通过state控制展开状态,完全自定义符合规范的表格DOM:

<div className="row me-2 ms-2">
  <table className="table accordian-table table header-fixed border mt-2">
    <thead>
      <tr>
        <th width="30%" className="text-center">Col 1</th>
        <th width="30%" className="text-center">Col 2</th>
        <th width="30%" className="text-center">Col 3</th>
        <th width="25px" className="float end"></th>
      </tr>
    </thead>
    <tbody className="scroll">
      {items?.length ? (
        [...items].flatMap((item, index) => {
          const isExpanded = activeAccordionKey === index;
          return [
            // 主数据行
            <tr 
              key={`main-${index}`} 
              onClick={() => {
                getFlows(item);
                setActiveAccordionKey(isExpanded ? null : index);
              }}
              className="main-table-content"
            >
              <td width="30%" title={item.prop1} className="text-center pt-2">
                {item.prop1}
              </td>
              <td width="30%" title={item.prop2} className="text-center pt-2">
                {item.onboardingInfo.prop2}
              </td>
              <td width="30%" title={item.prop3} className="text-center pt-2">
                {item.onboardingInfo.prop3}
              </td>
              <td width="25px">{" "}</td>
            </tr>,
            // 展开内容行:根据状态显示/隐藏
            isExpanded && (
              <tr key={`expand-${index}`}>
                <td colSpan="4" onClick={(e) => e.stopPropagation()}>
                  <table className="table">
                    <thead>
                      <tr>
                        <th>Flow Name</th>
                        <th>Flow Type</th>
                        <th>Dnid</th>
                        <th>Ext</th>
                        <th>Created By</th>
                        <th>Created On</th>
                      </tr>
                    </thead>
                    <tbody>
                      {selectedItem?.length ? (
                        [...selectedItem.values()].map((slItem) => (
                          <tr key={slItem.flowName}>
                            <td>{slItem.flowName}</td>
                            <td>{slItem.flowTypeId}</td>
                            <td>{slItem.dnid}</td>
                            <td>{slItem.createdBy}</td>
                            <td>{slItem.createdOn}</td>
                          </tr>
                        ))
                      ) : (
                        <tr>
                          <td>No Configs Available</td>
                        </tr>
                      )}
                    </tbody>
                  </table>
                </td>
              </tr>
            )
          ].filter(Boolean);
        })
      ) : (
        <tr>
          <td colSpan="4">No ItemsFound</td>
        </tr>
      )}
    </tbody>
  </table>
</div>

这个方案完全脱离Accordion组件的约束,通过activeAccordionKey直接控制展开行的显示,DOM结构完全符合HTML表格规范,不会出现任何嵌套警告。

警告原因说明

HTML规范明确规定,<tr>的直接子元素只能是<td>、<th>等表格相关元素,而React Bootstrap的Accordion组件默认会渲染<div>元素,将其嵌套在<tr>内部就违反了DOM嵌套规则,从而触发控制台警告。上面两个方案都从结构上规避了这个问题,同时保留了原有的行展开功能。

内容的提问来源于stack exchange,提问作者Shaan Srivastava

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 13:44:55