How to Make a Table in HTML (with Borders & Styling)

Quick answer

<table> <tr> <th>Name</th> <th>Age</th> </tr> <tr> <td>Ana</td> <td>28</td> </tr> </table>

Step 1: Build a basic table

An HTML table is built row by row. You never create columns directly: the columns appear because every row has the same number of cells.

  1. Start with <table> and </table>.
  2. Add a row with <tr> (table row).
  3. In the first row, use <th> (table header) for each column heading. Browsers show them bold and centered.
  4. Add more rows, using <td> (table data) for each normal cell.

Try adding a fourth row in the example below: copy one <tr> block and change the text.

index.html
Preview

Without any CSS the table has no borders and very little spacing, which makes it hard to read. Step 3 fixes that.

Step 2: Add thead, tbody and a caption

For anything beyond a tiny table, group the rows into sections and give the table a title:

  • <caption>: the table’s title, placed right after <table>. Screen readers announce it, which helps people understand what the table is about.
  • <thead>: wraps the header row(s).
  • <tbody>: wraps the main data rows.
  • <tfoot>: wraps summary rows such as totals.

These sections don’t change how the table looks by default, but they make it easier to style (for example, only the header row), they help assistive technology, and when a long table is printed, browsers can repeat the header on every page.

Step 3: Add borders and style the table with CSS

The old border="1" attribute still works, but CSS gives you full control. Two rules matter most:

  1. Put border: 1px solid #ccc on th and td to draw a line around each cell.
  2. Put border-collapse: collapse on table, so neighbouring cells share one line instead of showing double borders.
  3. Add padding to the cells for breathing room, and text-align: left on headers if you prefer them aligned with the data.
  4. Optional: color every other row with tr:nth-child(even) (“zebra stripes”) and highlight a row on hover.
index.html
Preview

Right-aligning number columns (the num class above) makes figures much easier to compare, because the digits line up.

By default the browser sizes each column to fit its content. To control widths yourself, set width on the header cells (for example th:first-child { width: 40%; }), or add table-layout: fixed to the table: columns then take the widths you give the first row, and long text wraps instead of stretching the table. Fixed layout also renders large tables faster, because the browser doesn’t have to measure every cell first.

Step 4: Merge cells with colspan and rowspan

Sometimes one cell needs to stretch across several columns or rows, like a heading over a group of columns or a time slot that lasts two hours:

  • colspan="2" makes a cell two columns wide. Leave out one cell in that row to make room for it.
  • rowspan="2" makes a cell two rows tall. Leave out one cell in the row below.

If the table suddenly looks lopsided, count the cells: every row must add up to the same number of columns once spans are included.

index.html
Preview

Step 5: Make tables work on phones

A table with many columns is wider than a phone screen. Squeezing it makes the text unreadable, so the simplest fix is to let the table scroll sideways inside its own box while the rest of the page stays put:

  1. Wrap the table in a <div class="table-scroll">.
  2. Give that div overflow-x: auto.
  3. Optionally give the table a min-width, so its columns keep a readable size.

The table is wider than the preview, so drag or scroll it sideways inside its box; the rest of the page stays put.

index.html
Preview

Make tables accessible

Screen readers read tables cell by cell and announce the matching header before each value (“Age, 28”). That only works when the table tells them which cells are headers:

  • Use <th> for every header cell, including the first cell of a row when it labels that row (like the times in the schedule example above).
  • Add scope when it isn’t obvious: scope="col" for a column header, scope="row" for a row header.
  • Give the table a <caption> so people know what it shows before they start reading the cells.
  • Keep tables simple. Several levels of merged headers are hard to follow by ear. Splitting one complex table into two simpler ones often helps everyone.

HTML table tags at a glance

TagWhat it does
<table>Wraps the whole table
<caption>The table’s title (first thing inside <table>)
<thead>, <tbody>, <tfoot>Group the header, body and footer rows
<tr>One row
<th>A header cell (bold, centered, announced as a heading); use scope="col" or scope="row" in complex tables
<td>A normal data cell
<colgroup> / <col>Style whole columns, e.g. a width or background

Common mistakes when making tables

  • Using tables for page layout. Tables are for data in rows and columns. Use CSS flexbox or grid to arrange a page.
  • Rows with different cell counts. Every row must add up to the same number of columns (counting colspan), or cells shift out of place.
  • Double borders. Forgetting border-collapse: collapse leaves a gap between every cell’s border.
  • Using bold <td>s instead of <th>. Real header cells tell screen readers what each column means.
  • No caption. A <caption> (or a heading right before the table) explains what the data is.
  • Wide tables breaking phone layouts. Wrap them in a scrolling container.

Frequently asked questions

How do I create a table in HTML?
Use a <table> element, add one <tr> for each row, and put <th> cells in the header row and <td> cells in the other rows. Every row should have the same number of cells.
How do I add borders to an HTML table?
Use CSS: th, td { border: 1px solid #ccc; } and table { border-collapse: collapse; }. The collapse rule makes neighbouring cells share a single line instead of showing double borders.
What is the difference between th and td?
<th> is a header cell that labels a column or row; browsers show it bold and centered and screen readers announce it as a heading. <td> is a normal data cell.
How do I merge cells in an HTML table?
Use colspan to make a cell span several columns (colspan="2") or rowspan to make it span several rows (rowspan="2"), and remove the cells it replaces from the row or rows it covers.
How do I make an HTML table responsive?
Wrap the table in a div with overflow-x: auto. On small screens the table then scrolls sideways inside its box instead of squeezing its text or widening the whole page.
How do I center a table in HTML?
Give the table margin: 0 auto in CSS. Because a table is only as wide as its content, the automatic left and right margins push it to the middle of its container.