Question Details

No question body available.

Tags

html css css-selectors

Answers (3)

August 16, 2025 Score: 2 Rep: 84,475 Quality: Medium Completeness: 60%

Assuming that the table has been created by the HTML parser, the most direct way is to find the first child element of the table that contains a tr element. These days, there's a way to express that in a Selector. table > :nth-child(1 of :has(tr)).

Having found that, while the first child element would normally be a tr element, it's possible that it's a script or template element, so the full selector needs to find the first tr child. So table > :nth-child(1 of :has(tr)) > tr:first-of-type

table > :nth-child(1 of :has(tr)) > tr:first-of-type {
  background: blue;
}

  Table Case: thead has a tr
  

First row of thead
Second row of thead
First row of first tbody
Second row of first tbody
First row of second tbody
Second row of second tbody
First row of tfoot
Second row of tfoot

Table Case: thead has no tr

First row of first tbody
Second row of first tbody
First row of second tbody
Second row of second tbody
First row of tfoot
Second row of tfoot

Table Case: thead not present

First row of first tbody
Second row of first tbody
First row of second tbody
Second row of second tbody
First row of tfoot
Second row of tfoot

Table Case: Caption not present

First row of thead
Second row of thead
First row of first tbody
Second row of first tbody
First row of second tbody
Second row of second tbody
First row of tfoot
Second row of tfoot


If the table is HTML valid, but not created by the HTML parser, i.e. by the XML parser or by JavaScript, then the table may contain direct child tr elements. This makes the problem somewhat trickier, and the neatest solution I can see is to use nesting:

table > :nth-child(1 of tr, :has(tr)) {
  &:is(tr), > tr:first-of-type {
    ...
  }
}

const tbl = document.getElementById("tr-children");
const tfoot = tbl.querySelector('tfoot');
tbl.insertBefore(Object.assign(document.createElement('tr'), { 
  innerHTML: 'first tr'
}), tfoot);
tbl.insertBefore(Object.assign(document.createElement('tr'), { 
  innerHTML: 'second tr'
}), tfoot);
table > :nth-child(1 of tr, :has(tr)) {
  &:is(tr), > tr:first-child {
    background: blue;
  }
}

  Table Case: tr children added by JS

First row of tfoot
Second row of tfoot

Table Case: thead has a tr

First row of thead
Second row of thead
First row of first tbody
Second row of first tbody
First row of second tbody
Second row of second tbody
First row of tfoot
Second row of tfoot

Table Case: thead has no tr

First row of first tbody
Second row of first tbody
First row of second tbody
Second row of second tbody
First row of tfoot
Second row of tfoot

Table Case: thead not present

First row of first tbody
Second row of first tbody
First row of second tbody
Second row of second tbody
First row of tfoot
Second row of tfoot

Table Case: Caption not present

First row of thead
Second row of thead
First row of first tbody
Second row of first tbody
First row of second tbody
Second row of second tbody
First row of tfoot
Second row of tfoot

August 5, 2025 Score: 2 Rep: 1,804 Quality: Low Completeness: 30%

table:not(:has(thead>tr))>tbody>tr:first-child, table:has(thead>tr)>thead>tr:first-child
August 5, 2025 Score: 1 Rep: 11,750 Quality: Medium Completeness: 60%

It's possible. This may not be the ideal solution:

table {
  & > :is(thead, tbody, tfoot) {
    tr:first-of-type {
      background: red;
      & ~ tr {
        background: unset;
        tr {
          background: unset;
        }
      }
    }
    &:has(tr:first-of-type) {
      & ~ :is(thead, tbody, tfoot) {
        tr {
          background: unset;
        }
      }
    }
  }
}

  Table Title
  

123
123
123
123122
123
123
123122
123
123122
123