O with occluded right edge to appear also as a C Open Web Components Guides Docs Blog

EsLint Plugin Lit A11y: heading-has-content

Enforce that heading elements (h1, h2, etc.) have content and that the content is accessible to screen readers. Accessible means that it is not hidden using the aria-hidden attribute. Refer to the references to learn about why this is important.

Rule Details

This rule aims to...

Examples of incorrect code for this rule:

html`
  <h1>
    <div aria-hidden="true">foo</div>
  </h1>
`;
html` <h1></h1> `;

Examples of correct code for this rule:

html` <h1>Foo</h1> `;
html`
  <h1>
    <div aria-hidden="true">foo</div>
    foo
  </h1>
`;

Options

The customHeadingElements option lets you specify tag names to include in this rule, for example, if you have a custom element which implements heading semantics.

customElements.define(
  'custom-heading',
  class CustomHeading extends HTMLElement {
    static get observedAttributes() {
      return ['level'];
    }

    get level() {
      const parsed = parseInt(this.getAttribute('level'));
      if (!Number.isNaN(parsed)) return parsed;
      else return null;
    }

    constructor() {
      super();
      this.attachShadow({ mode: 'open' });
    }

    connectedCallback() {
      this.render();
    }

    attributeChangedCallback() {
      if (typeof this.level === 'number') this.render();
    }

    render() {
      const heading = `h${this.level}`;
      this.shadowRoot.innerHTML = `
      <${heading}>
        <slot></slot>
      </${heading}>
    `;
    }
  },
);
{
  "rules": {
    "lit-a11y/heading-has-content": [
      "error",
      {
        "customHeadingElements": ["custom-heading"]
      }
    ]
  }
}

Examples of incorrect code with customHeadingElements: ["custom-heading"]:

html` <custom-heading></custom-heading> `;

Examples of incorrect code with customHeadingElements: ["custom-heading"]:

html`
  <custom-heading>Heading</custom-heading>
  <custom-heading><span>Heading</span></custom-heading>
  <custom-heading>${foo}</custom-heading>
`;

Further Reading