Skip to content

Commit ddff21a

Browse files
Merge pull request #2713 from johanrd/fix/template-no-nested-interactive-details
BUGFIX: false positive: interactive flow content inside <details>
2 parents f211ee4 + a3ac079 commit ddff21a

2 files changed

Lines changed: 15 additions & 7 deletions

File tree

lib/rules/template-no-nested-interactive.js

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,19 +45,23 @@ function isMenuItemNode(node) {
4545
return getTextAttr(node, 'role') === 'menuitem';
4646
}
4747

48-
function isSummaryFirstChildOfDetails(summaryNode, parentEntry) {
49-
if (summaryNode.tag !== 'summary' || parentEntry.tag !== 'details') {
48+
function isAllowedDetailsChild(childNode, parentEntry) {
49+
if (parentEntry.tag !== 'details') {
5050
return false;
5151
}
52-
const parentNode = parentEntry.node;
53-
const children = parentNode.children || [];
52+
// Non-<summary> children are flow content in the disclosed panel — allowed.
53+
// <summary> is only allowed as the first non-whitespace child of <details>.
54+
if (childNode.tag !== 'summary') {
55+
return true;
56+
}
57+
const children = parentEntry.node.children || [];
5458
const firstNonWhitespace = children.find((child) => {
5559
if (child.type === 'GlimmerTextNode') {
5660
return child.chars.trim().length > 0;
5761
}
5862
return true;
5963
});
60-
return firstNonWhitespace === summaryNode;
64+
return firstNonWhitespace === childNode;
6165
}
6266

6367
/** @type {import('eslint').Rule.RuleModule} */
@@ -208,8 +212,8 @@ module.exports = {
208212
});
209213
}
210214
parentEntry.interactiveChildCount++;
211-
} else if (isSummaryFirstChildOfDetails(node, parentEntry)) {
212-
// <summary> as first non-whitespace child of <details> is allowed
215+
} else if (isAllowedDetailsChild(node, parentEntry)) {
216+
// flow content in the disclosed panel, or <summary> as first child
213217
} else if (isMenuItemNode(parentEntry.node) && isMenuItemNode(node)) {
214218
// Nested menuitem nodes are valid (menu/sub-menu pattern)
215219
} else {

tests/lib/rules/template-no-nested-interactive.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ ruleTester.run('template-no-nested-interactive', rule, {
6161
},
6262
'<template><details><summary>Details</summary>Something small enough to escape casual notice.</details></template>',
6363
'<template><details> <summary>Details</summary>Something small enough to escape casual notice.</details></template>',
64+
'<template><details><summary>Advanced</summary><label for="x">Field</label><input id="x" /></details></template>',
65+
'<template><details><summary>More</summary><div><button type="button">Action</button></div></details></template>',
6466
`<template>
6567
<ul role="menubar" aria-label="functions" id="appmenu">
6668
<li role="menuitem" aria-haspopup="true">
@@ -249,6 +251,8 @@ hbsRuleTester.run('template-no-nested-interactive', rule, {
249251
'<label><input></label>',
250252
'<details><summary>Details</summary>Something small enough to escape casual notice.</details>',
251253
'<details> <summary>Details</summary>Something small enough to escape casual notice.</details>',
254+
'<details><summary>Advanced</summary><label for="x">Field</label><input id="x" /></details>',
255+
'<details><summary>More</summary><div><button type="button">Action</button></div></details>',
252256
`
253257
<ul role="menubar" aria-label="functions" id="appmenu">
254258
<li role="menuitem" aria-haspopup="true">

0 commit comments

Comments
 (0)