When building interactive disclosure widgets in HTML, the <details> element is a powerful, native tool. However, it is often misused or left incomplete. To ensure a consistent and accessible user experience, the @html-eslint/require-details-summary rule is a must-have in your linting configuration.
Why This Rule Matters
The HTML Standard is explicit about the structure of a disclosure widget. According to the specification:
The first summary element child of the element, if any, represents the summary or legend of the details. If there is no child summary element, the user agent should provide its own legend (e.g. “Details”).
Furthermore, the Content Model for the <details> element is defined as:
One summary element followed by flow content.
Violating this rule by omitting the summary is problematic for two main reasons:
UX: A generic “Details” label rarely describes the specific content contained within the widget, leading to a confusing interface.
Accessibility: Screen reader users rely on the summary text to understand the purpose of the interactive element before toggling it. Without a specific summary, the user loses context.
Zero-Config with @ethang/eslint-config
If you are using @ethang/eslint-config, you don’t need to manually define this rule. It is enabled by default within the HTML subconfig.
To use it, simply include htmlConfig in your eslint.config.js file:
import config from "@ethang/eslint-config/config.main.js";
import { defineConfig, globalIgnores } from "eslint/config";
import htmlConfig from "@ethang/eslint-config/config.html.js"; // Import the HTML subconfig
export default defineConfig(
globalIgnores(["dist", "node_modules"]),
...config,
...htmlConfig, // The rule is now active for all .html files
{
languageOptions: {
parserOptions: {
project: true,
tsconfigRootDir: import.meta.dirname,
},
},
},
);
Correct vs. Incorrect Implementation
The linter enforces the specification by ensuring the <summary> is present and positioned correctly as the first child.
❌ Incorrect
<!-- Missing the summary element entirely -->
<details>
<p>Hidden content</p>
</details>
<!-- The summary is not the first child -->
<details>
<p>Content before summary</p>
<summary>Toggle</summary>
</details>
✅ Correct
<details>
<summary>Show more</summary>
<p>Hidden content</p>
</details>
By enforcing this rule, you guarantee that your disclosure widgets are always labeled correctly, following the HTML spec and providing a better experience for all users.
Further Reading: