HTML & CSS table with progress bars

I updated the tables I used in my recent 'Learning Log 2022' article with percentage indicators and have shared the HTML & CSS.

Background

I recently created my first HTML tables for my Learning Log 2022 article. Each row in the table was a course or book I had used during the previous year, and I wanted to add a progress indicator within the rows to show my progress. It took some effort to get the tables looking and functioning the way I wanted (mostly due to declaring the progress variable in the HTML and not the CSS) so I thought the solution was worth sharing.

The difference between the table shown below and those used in my previous article is the inclusion of the percentage value. That required a little hack that takes advantage of CSS Counters.

The result

The table, CSS, and HTML are all included below. You can also visit CodePen to see (and edit) the table. The CodePen version includes some helpful comments in the CSS.

FormatResourceProgress
LinkedIn's ‘Become a data analyst’
W3School's ‘SQL tutorial’
DBeaver User Manual
PL-300: Power BI Data Analyst
The table with progress indicators.

Notes and code

The tags in the first column are added via ::before pseudo-elements.

The second column will use an ellipsis when the text is too long for the column (there's a special place in Hell for people who build tables with unequal row-heights).

For the third column, the percentage progress for each row is declared in the HTML as a CSS Variable. This is then used to set the progress bar length, and also the percentage text. If the percentage is equal to 100%, then the text is swapped for a “✓” and the progress bar colour is changed to green.

To show the percentage value alongside the progress bar (without including it as separate text in the HTML or CSS) I define a CSS counter-reset and set it to the progress variable. I then use the ::before element where the content is set to the CSS counter value (nothing has been “counted”, so this is equal to the counter-reset i.e. the progress variable). It's a bit of a hack that allows me to get a CSS Variable displayed as text on the page.

The CSS used to style the table:

* {
  font-family: Sans-serif;
}

table {
  width: 80%;
  max-width: 700px;
  table-layout: fixed;
  margin: auto;
  text-align: left;
  margin-top: 50px;
  border-collapse: collapse;
  box-shadow: 0px 0px 10px 1px rgb(0 0 0 / 15%);
  border-radius: 10px;
  overflow: hidden; 
  line-height: 2.5rem;
}

th {
  background-color: AliceBlue;
}

th,
td {
  padding: 6px 10px;
}

th:nth-child(1) {
  width: 70px;
}

td:nth-child(2) {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

th:nth-child(3) {
  width: 30%;
}

progress-meter {
  display: block;
  height: 10px;
  box-shadow: 0px 0px 6px 1px rgba(0, 0, 0, 0.1);
  border-radius: 5px;
  padding: 1px;
  margin-right: 2rem;
  position: relative;
}

progress-percent {
  display: block;
  height: 100%;
  border-radius: 5px;
  width: calc(var(--progress) * 1%); 
  background-color: IndianRed;
  font-size: 70%;
  color: grey;
}

progress-percent[style="--progress: 100"] {
  background-color: MediumAquamarine;
}

progress-percent::after {
  counter-reset: percent var(--progress);
  content: counter(percent) '%';
  position: absolute;
  right: -2rem;
  bottom: -0.9rem;
}

progress-percent[style="--progress: 100"]::after {
  content: '✓';
  right: -1rem;
  bottom: -0.9rem;
}


/* define the shared tag styles */
:where(course-tag, tutorial-tag, book-tag):before {
  font-size: 0.8rem;
  color: white;
  border-radius: 3px;
  padding: 1px 5px;
}

course-tag:before {
  background-color: MediumVioletRed;
  content: "course";
}

tutorial-tag:before {
  background-color: SteelBlue;
  content: "tutorial";
}

book-tag:before {
  background-color: MediumPurple;
  content: "book";
}

The HTML used to generate the table:

<table>

  <thead>
    <tr>
      <th>Format</th><th>Resource</th><th>Progress</th>
    </tr>
  </thead>
  
  <tbody>
    
    <tr>
      <td><course-tag></course-tag></td>
      <td>LinkedIn's ‘Become a data analyst’</td>
      <td>
        <progress-meter>
          <progress-percent style="--progress: 25"></progress-percent>
        </progress-meter>
      </td>
    </tr>
    
    <tr>
      <td><tutorial-tag></tutorial-tag></td>
      <td>W3School's ‘SQL tutorial’</td>
      <td>
        <progress-meter>
          <progress-percent style="--progress: 100"></progress-percent>
        </progress-meter>
      </td>
    </tr>
    
    <tr>
      <td><book-tag></book-tag></td>
      <td>DBeaver User Manual</td>
      <td>
        <progress-meter>
          <progress-percent style="--progress: 75"></progress-percent>
        </progress-meter>
      </td>
    </tr>
    
    <tr>
      <td><course-tag></course-tag></td>
      <td>PL-300: Power BI Data Analyst</td>
      <td>
        <progress-meter>
          <progress-percent style="--progress: 60"></progress-percent>
        </progress-meter>
      </td>
    </tr>
    
  </tbody>
  
</table>