Tables are commonly used in HTML to organize and display data. Their uses are wide-ranging, and they help to make it easier to pass information to a webpage’s users.
In today’s tutorial, we will cover the basics of tables in HTML, include how to use required tags and CSS styles in your tables.
This is the perfect place to start your journey as a front-end developer. With no prior knowledge needed, you will learn how to build beautiful, functional websites.
A table is a structured set of data arranged in rows and columns. Tables are widely used for data presentation and data analysis, and they are used frequently in books, scientific journals, and websites.
HTML, which stands for HyperText Markup Language, is a markup language used to instruct web browsers how they should display web pages. The latest iteration of HTML (HTML5) comes with robust support for displaying data using complex or simple tables.
When we define a table element, we use the following tags:
<table>: defines an HTML table<tr>: defines each table row<th>: defines each table row<th>: defines each table header<td>: defines each table data or cellNote: all
<th>elements are bold and centered by default, and the<td>text elements are left-aligned.
There are many other HTML elements that can be used to customize the appearance and structure of tables. These include <thead>, <tbody>, <tfoot>, which we will discuss later.
It is important to note that tables should be functional. That means, the data or information displayed in your table should be easy to read and understand. If you do not have an idea how your table should be formatted, you can make a sketch on paper. This will help you to visualize and organize the table before you write code.
Most tables need some sort of text that describes the purpose of the table. We can use the <caption> element to solve this problem. It is optional. But since it displays the caption (or title) of the table, it helps with ease of use and accessibility.
When in use, it comes right after the <table> opening tag and is followed by a matching closing tag:
<caption>Neonates Immunization Table</caption>
It is also common to have table cells that describe groups of data within a table. The <thead> element defines a set of rows which represent the head of columns of the table. It is an optional element and can come either right after the <table> tag or the </caption> tag when available.
The <th> tag marks a cell as a table header, and it is usually at the start of a row or column. <th> tags are always used within a <tr> tag and they with some default styling to help them stand out.
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">Sex</th>
<th scope="col">Weight(kg)</th>
<th scope="col">Immunization Doses</th>
</tr>
</thead>
HTML tables are more than just rows and columns — they’re essential for presenting structured data in an accessible way.
To ensure everyone, including screen-reader users, can understand and navigate your data, follow these best practices.
Always define headers using the <th> element.
Add a scope attribute to make relationships between headers and data cells explicit:
<th scope="col">Name</th>
<th scope="row">Total</th>
This helps assistive technologies understand which headers apply to which cells.
For tables with multiple levels of headers (such as grouped columns or nested rows), use the id and headers attributes to associate each data cell with the correct header:
<th id="month">Month</th>
<th id="sales">Sales</th>
<td headers="month sales">January 2025</td>
This ensures that screen readers announce the correct context when users navigate through complex tables.
Use native HTML elements whenever possible — they have built-in accessibility support.
Only add ARIA roles like role="grid" or aria-labelledby when creating highly interactive or custom table-like components.
A <caption> gives context about what the table represents:
<table>
<caption>Monthly Sales Report – Q1 2025</caption>
...
</table>
Screen readers announce captions first, helping users understand what data they’re about to explore.
Following these practices ensures your tables are semantically correct, screen-reader friendly, and compliant with accessibility standards.
Accessible design isn’t just about inclusion — it’s also about clarity and usability for everyone.
The <tfoot> element is an optional element that defines a set of rows summarizing the columns of the table layout. It usually comes after the <tbody> tag.
<tfoot>
<th>Mean Weight (kg)</th>
<td>2.9</td>
</tfoot>
Learn HTML without scrubbing through videos or documentation. Educative’s text-based learning paths are easy to skim and feature live coding environments, making learning quick and efficient.
In the past, borders could be added to your HTML Table using the border attribute, which takes in a number that is automatically in pixels. This attribute can only be added to the <table> tag and it gives the table and every cell a border.
<table border='1'>
<tr>
<th >Jerry Holmes</th>
<td>M</td>
<td>5</td>
<td>0</td>
<td>3.5</td>
</tr>
</table>
This behavior was deprecated in HTML5 in favor of the CSS border property. With this change, one can now add borders across the table or to individual elements. If you don’t want your cells to have separate borders, you should set the border-collapse property to collapse. Otherwise adjacent cells would have distinct borders.
table {
border-collapse: collapse;
}
td, th {
border: 1px solid rgba(0, 0, 0, 0.5);
}
In the next section I would show you how to create tables with a complex layout, where table cells can span multiple rows or a number of columns.
In the table we are building, notice that the “Mean Weight” cell spans more than one cell, and the “Immunization Doses” seems like a “Super Heading” with subheadings (taken and left).
This behavior is made possible with the colspan and rowspan attributes. Both attributes accept a number value, which is the number of rows or columns you want spanned.
<thead>
<tr>
<th rowspan="2">Name</th>
<th rowspan="2">Sex</th>
<th colspan="2">Immunization Doses</th>
<th rowspan="2">Weight(kg)</th>
<tr>
<th>Taken</th>
<th>Left</th>
</tr>
</tr>
</thead>
The rowspan attribute enables the contents of a table cell span multiple rows. In the code sample above, we’ve made the "Name", "Sex", and "Weight" heading cells span two rows.
The colspan makes a single table cell span the width of more than one column or data cells. Using the colspan attribute, we make the “Immunization Doses” heading span two columns (and a single row). Then, by adding the subheadings to the next row, they are automatically added under “Immunization Doses”.
Some table styling attributes are no longer supported in HTML5; corresponding CSS properties have replaced them. Some of these attributes include:
align: use CSS margin-left, margin-right, or margin: auto properties instead.bgcolor: to achieve a similar effect, use the CSS background-color propertyborder: use CSS border shorthand propertywidth: use CSS width propertyCellspacing and cellpadding can be achieved using border-spacing and padding respectively. border-spacing does not have any effect if border-collapse is set to collapse.
The color and other attributes of text within cells can be modified by specifying the value of a relevant attribute, such as color, font-size, and font-family, using an appropriate selector.
thead,
tfoot {
font-size: 18px;
}
One of the biggest challenges with tables is how they behave on smaller screens.
Traditional tables don’t adapt well, but several responsive design techniques can help make them usable across devices.
Wrap your table in a scrollable container using horizontal overflow.
This approach is accessible, simple, and widely supported.
.table-container {overflow-x: auto;}
<div class="table-container"><table><!-- table content --></table></div>
Users can now scroll horizontally on smaller screens without losing data visibility.
For extremely small screens, you can use CSS to stack each row’s data into card-style blocks.
This method improves readability on mobile devices but can reduce clarity for complex datasets.
@media (max-width: 600px) {table, thead, tbody, th, td, tr {display: block;}td::before {content: attr(data-label);font-weight: bold;display: block;}}
This transforms each row into a self-contained card.
Combine horizontal scrolling for moderate screen sizes with stacked layouts on very small screens.
Use media queries to progressively enhance the experience across breakpoints.
Responsive tables ensure your data remains readable, usable, and accessible on every device — a must for modern web design.
Large datasets benefit from keeping headers or columns visible during scrolling.
You can achieve this with pure CSS:
th {position: sticky;top: 0;background: white;z-index: 1;}
This keeps <th> elements fixed at the top of the viewport as users scroll.
To freeze the first column, use:
td:first-child, th:first-child {position: sticky;left: 0;background: white;}
These small improvements dramatically enhance usability for large data tables.
Use <colgroup> and <col> to apply styles to entire columns without repeating classes or inline CSS.
This is useful when highlighting specific data types like totals or dates.
<table><colgroup><col style="background-color: #f8f8f8;"><col><col style="background-color: #e0f7fa;"></colgroup><tr><th>Product</th><th>Price</th><th>Stock</th></tr></table>
<colgroup> makes your table code cleaner and more maintainable, especially for large datasets.
Rendering massive tables can hurt page performance.
Here’s how to optimize them:
Use table-layout: fixed; to stabilize column widths and speed up rendering.
Set explicit column widths to prevent layout shifts.
Paginate or virtualize rows to limit the DOM size.
Defer rendering with lazy loading or server-side rendering if the table appears below the fold.
These techniques are essential for enterprise dashboards and data-heavy applications.
If your tables are intended for printing (e.g., invoices, reports, summaries), use semantic structure:
<table><thead> ... </thead><tbody> ... </tbody><tfoot> ... </tfoot></table>
Browsers automatically repeat <thead> on each printed page, while <tfoot> can show summaries.
This improves readability both on-screen and in print.
Finally, remember: tables are for data, not layout.
For page structure and positioning, use CSS Grid or Flexbox.
These modern layout systems are more flexible, powerful, and accessible — keeping structure and presentation cleanly separated.
That concludes what we need to know in order to get started implementing tables in HTML. You can take what you’ve learned here, and your existing HTML and CSS knowledge, to start designing and implementing beautiful and functional tables.
The next steps to learn to master HTML and CSS are:
If you would like to learn HTML and CSS from scratch, check out Educative’s learning path Become a Front End Developer. With no prior knowledge needed, you will gain a mastery of HTML, CSS, and JavaScript and learn how to build beautiful websites on your own.
Happy learning!