<tr>, <td> & <th> Tags in HTML

Quick facts

CategoryNone of their own — they are only allowed inside tables
Content model<tr>: zero or more <td>/<th>. <td>: flow content. <th>: flow content, but no headings, sectioning, <header> or <footer>
Tag omissionEnd tags may be omitted when another row or cell follows, but writing them is best practice
Permitted parents<tr>: <table>, <thead>, <tbody> or <tfoot>. <td>/<th>: a <tr>
DOM interfacesHTMLTableRowElement, HTMLTableCellElement (<td> and <th>)

Syntax

<tr> <th scope="row">Monday</th> <td>9:00</td> <td colspan="2">Closed in the afternoon</td> </tr>

Live example

Edit the code below and watch the preview update instantly.

index.html
Preview

Attributes

<td> and <th>

AttributeDescription
colspanHow many columns the cell spans (default 1)
rowspanHow many rows the cell spans (default 1)
headersSpace-separated ids of the <th> cells that label this cell, for complex tables

<th> only

AttributeDescription
scopeWhich cells this header labels: col, row, colgroup or rowgroup
abbrA short version of the header text for screen readers to repeat

<tr>

AttributeDescription
—Only the global attributes apply.

Common examples

Row and column headers

scope says whether a th is a header for its column or its row.

<table> <tr><th scope="col">Plan</th><th scope="col">Price</th></tr> <tr><th scope="row">Basic</th><td>$5</td></tr> <tr><th scope="row">Pro</th><td>$15</td></tr> </table>

Merging cells

colspan spans columns and rowspan spans rows.

<table> <tr><th colspan="2">Opening hours</th></tr> <tr><td>Mon–Fri</td><td>9–17</td></tr> <tr><td rowspan="2">Weekend</td><td>Sat 10–14</td></tr> <tr><td>Sun closed</td></tr> </table>

Adding rows with JavaScript

insertRow and insertCell create rows without writing HTML strings.

<table id="t"></table> <script> const row = t.insertRow(); row.insertCell().textContent = "Tea"; row.insertCell().textContent = "$3"; </script>

Cells that stack on phones

On small screens, show each row as a card with the column name before each value.

<td data-label="Price">$5</td> <style> @media (max-width: 600px) { tr, td { display: block; } td::before { content: attr(data-label) ": "; font-weight: bold; } } </style>

scope vs the headers attribute

Screen readers need to know which header belongs to each data cell. For normal tables with one header row and/or one header column, scope="col" and scope="row" on your <th> cells are all you need.

For complex tables — several header levels or merged header cells — give every th an id and list the matching ids in each td’s headers attribute. It’s precise but laborious, so it’s often better to split a complex table into simpler ones.

scopeheaders
Goes on<th><td> (lists th ids)
EffortLowHigh
Best forSimple tablesComplex, multi-level tables

Common mistakes to avoid

  • Bold td cells instead of th. Bold styling doesn’t make a header; screen readers won’t know.
  • Rows with different cell counts. Without matching colspan, columns shift and the table breaks.
  • Empty cells for spacing. Use CSS padding, not extra cells.
  • Tables for layout. Arrange page sections with CSS grid or flexbox.

Accessibility & SEO tips

  • Keep tables simple — one header row and maybe one header column are easiest for everyone to read.
  • Abbreviated headers can carry the full name in an abbr attribute, for example <th abbr="Quantity">Qty</th>.
  • Real HTML tables (not images of tables) can be indexed by search engines and shown as table snippets in results.

Browser support

Supported in every browser, including Chrome, Edge, Firefox, Safari and their mobile versions — it has been part of HTML since the very first versions.

Related tags

Frequently asked questions

How do I merge cells in an HTML table?
Use colspan to stretch a cell across columns (colspan="2") and rowspan to stretch it down rows (rowspan="2"). Remove the cells it now covers from the following columns or rows, or the table will have extra cells.
When should I use <th> instead of <td>?
Use <th> for any cell that labels other cells, such as column titles or the first cell of each row. Add scope="col" or scope="row" so screen readers announce the right header with each data cell.
How do I give a table striped rows?
Use CSS: tbody tr:nth-child(even) { background: #f4f4f8; } colors every second row, which makes wide tables easier to read.
How do I center text in a table cell?
Use CSS: td { text-align: center; } for horizontal and vertical-align: middle; for vertical centering. The old align attribute is obsolete.
How do I add borders between table cells?
Use table { border-collapse: collapse; } and td, th { border: 1px solid #ccc; }.
What do tr, td and th stand for?
Table row, table data and table header.