htmlcsscss-counter

HTML Heading counter within table


I need to have text formatted in table where second column contains the text, some rows contains heading H1 - H5. I would like to use auto numbering for the heading but the increment does not work within table.

Problem is that the H2 level counter is not increasing there is always 1.1 as the heading number.

Can you please help, where is the problem?

body {
  counter-reset: h1counter;
}

h1 {
  counter-reset: h2counter;
}

h2 {
  counter-reset: h3counter;
}

h1:before {
  counter-increment: h1counter;
  content: counter(h1counter) ". ";
}

h2:before {
  counter-increment: h2counter;
  content: counter(h1counter) "."counter(h2counter) ". ";
}

h3:before {
  counter-increment: h3counter;
  content: counter(h1counter) "."counter(h2counter) "."counter(h3counter) ". ";
}
<table>
  <tbody>
    <tr>
      <td>1</td>
      <td>
        <h1>Heading 1</h1>
      </td>
    </tr>
    <tr>
      <td>2</td>
      <td>
        <h2>Heading 1.1</h2>
      </td>
    </tr>
    <tr>
      <td>3</td>
      <td>
        <h2>Heading 1.2</h2>
      </td>
    </tr>
    <tr>
      <td>4</td>
      <td>
        <h1>Heading 2.</h1>
      </td>
    </tr>
  </tbody>
</table>


Solution

  • Solution #1. This task can be solved using the counter-set CSS property. Example below:

    body {
      counter-reset: h1counter h2counter h3counter;
    }
    
    body h1 {
      counter-set: h2counter 0;
    }
    
    body h2 {
      counter-set: h3counter 0;
    }
    
    h1:before {
      counter-increment: h1counter;
      content: counter(h1counter) ". ";
    }
    
    h2:before {
      counter-increment: h2counter;
      content: counter(h1counter) "."counter(h2counter) ". ";
    }
    
    h3:before {
      counter-reset: h3counter;
    
      counter-increment: h3counter;
      content: counter(h1counter) "."counter(h2counter) "."counter(h3counter) ". ";
    }
    <table>
      <tbody>
        <tr>
          <td>1</td>
          <td>
            <h1>Heading 1</h1>
          </td>
        </tr>
        <tr>
          <td>2</td>
          <td>
            <h2>Heading 1.1</h2>
          </td>
        </tr>
        <tr>
          <td>3</td>
          <td>
            <h2>Heading 1.2</h2>
          </td>
        </tr>
        <tr>
          <td>4</td>
          <td>
            <h1>Heading 2.</h1>
          </td>
        </tr>
        <tr>
          <td>5</td>
          <td>
            <h2>Heading 2.1</h2>
          </td>
        </tr>
        <tr>
          <td>6</td>
          <td>
            <h2>Heading 2.2</h2>
          </td>
        </tr>
      </tbody>
    </table>

    Unfortunately, counter-set is a new property and is only supported by newer browsers and it doesn't work in Safari.

    Solution #2. Also, this problem can be solved with the help of JS and data attributes. Example below:

    let h1Counter = 0,
      h2Counter = 0,
      h3Counter = 0;
    
    document.querySelectorAll('h1, h2, h3').forEach((el) => {
      if (el.matches('h1')) {
        h1Counter++;
        h2Counter = 0;
        el.dataset.counter = `${h1Counter}`;
      } else if (el.matches('h2')) {
        h2Counter++;
        h3Counter = 0;
        el.dataset.counter = `${h1Counter}.${h2Counter}`;
      } else { // h3
        h3Counter++;
        el.dataset.counter = `${h1Counter}.${h2Counter}. ${h3Counter}`;
      }
    })
    h1:before,
    h2:before,
    h3:before {
      content: attr(data-counter) ". ";
    }
    <table>
      <tbody>
        <tr>
          <td>1</td>
          <td>
            <h1>Heading 1</h1>
          </td>
        </tr>
        <tr>
          <td>2</td>
          <td>
            <h2>Heading 1.1</h2>
          </td>
        </tr>
        <tr>
          <td>3</td>
          <td>
            <h2>Heading 1.2</h2>
          </td>
        </tr>
        <tr>
          <td>4</td>
          <td>
            <h1>Heading 2.</h1>
          </td>
        </tr>
        <tr>
          <td>5</td>
          <td>
            <h2>Heading 2.1</h2>
          </td>
        </tr>
        <tr>
          <td>6</td>
          <td>
            <h2>Heading 2.2</h2>
          </td>
        </tr>
      </tbody>
    </table>