HTML Tables: Structure, Headers, Styling and Accessibility

Use an HTML table to present tabular data whose meaning depends on rows and columns. A basic accessible table uses <table>, table rows with <tr>, header cells with <th>, and data cells with <td>.

<table>
  <caption>Student marks</caption>
  <thead>
    <tr>
      <th scope="col">Name</th>
      <th scope="col">Mark</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Alice</td>
      <td>85</td>
    </tr>
  </tbody>
</table>
Student marks
NameMark
Alice85
Do not use tables for page layout. Tables describe relationships between data cells and headers. Use CSS layout tools for page structure.

HTML Table Elements Top ↑

ElementPurpose
<table>Contains the table.
<caption>Provides a title or description for the table.
<thead>Groups header rows.
<tbody>Groups the main data rows.
<tfoot>Groups summary or footer rows.
<tr>Defines one table row.
<th>Defines a header cell.
<td>Defines a data cell.
<colgroup>Groups columns for shared styling or metadata.
<col>Represents one or more columns inside a colgroup.

Basic Table Top ↑

A table row is created with <tr>. Each normal data cell inside the row uses <td>.

<table>
  <tr>
    <td>Row 1, Column 1</td>
    <td>Row 1, Column 2</td>
  </tr>
  <tr>
    <td>Row 2, Column 1</td>
    <td>Row 2, Column 2</td>
  </tr>
</table>
The older border="1" presentation attribute is obsolete in modern HTML. Apply borders and spacing with CSS instead.

Table Headers with th and scope Top ↑

Use <th> for header cells. For simple tables, scope="col" or scope="row" makes the header relationship explicit.

Column headers Top ↑

<table>
  <thead>
    <tr>
      <th scope="col">Name</th>
      <th scope="col">Age</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Alice</td>
      <td>25</td>
    </tr>
  </tbody>
</table>

Row headers Top ↑

<table>
  <tr>
    <th scope="row">Alice</th>
    <td>85</td>
  </tr>
</table>

Do not use <td> merely because you want a header to look different. Use semantic <th> and style it with CSS.

Add a Table Caption Top ↑

A <caption> gives the table an accessible title and helps readers understand what the data represents.

<table>
  <caption>Monthly sales by product</caption>
  <tr>
    <th scope="col">Product</th>
    <th scope="col">Sales</th>
  </tr>
</table>

The caption belongs directly inside the table element.

thead, tbody and tfoot Top ↑

Use table section elements to group related rows.

<table>
  <caption>Order summary</caption>

  <thead>
    <tr>
      <th scope="col">Product</th>
      <th scope="col">Price</th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>Laptop</td>
      <td>$800</td>
    </tr>
  </tbody>

  <tfoot>
    <tr>
      <th scope="row">Total</th>
      <td>$800</td>
    </tr>
  </tfoot>
</table>

These elements improve structure and also make table manipulation easier in CSS and JavaScript.

Merge Columns with colspan Top ↑

colspan lets one cell span several columns.

<table>
  <tr>
    <th colspan="2" scope="colgroup">Full Name</th>
  </tr>
  <tr>
    <th scope="col">First</th>
    <th scope="col">Last</th>
  </tr>
</table>

Keep the logical number of columns consistent. A cell spanning two columns occupies the space of two normal cells.

Merge Rows with rowspan Top ↑

rowspan lets one cell span several rows.

<table>
  <tr>
    <th rowspan="2" scope="rowgroup">Science</th>
    <td>Physics</td>
  </tr>
  <tr>
    <td>Chemistry</td>
  </tr>
</table>
Merged cells are useful when they reflect the real data structure. Avoid complicated spanning purely for visual design because it can make tables harder to understand and maintain.

Style Tables with CSS Top ↑

Use CSS for borders, spacing, alignment and colors instead of old HTML presentation attributes such as border, cellpadding, cellspacing, align or fixed presentation widths.

<style>
  .data-table {
    width: 100%;
    border-collapse: collapse;
  }

  .data-table th,
  .data-table td {
    border: 1px solid #ccc;
    padding: 0.5rem;
    text-align: left;
  }

  .data-table tbody tr:nth-child(even) {
    background: #f7f7f7;
  }
</style>

<table class="data-table">
  <!-- table content -->
</table>

Responsive Tables Top ↑

Wide tables can overflow on small screens. A simple approach is to place the table inside a horizontally scrollable wrapper.

<div class="table-scroll" tabindex="0">
  <table>
    <!-- wide table -->
  </table>
</div>

<style>
  .table-scroll {
    overflow-x: auto;
  }
</style>

The wrapper preserves the table structure instead of hiding columns. The optional tabindex="0" can make the scrolling region keyboard-focusable when keyboard access to overflow is otherwise difficult; test the interaction in your target browsers and assistive technologies.

Table Accessibility Top ↑

For most simple data tables:

  • Add a meaningful <caption>.
  • Use <th> for actual headers.
  • Add scope="col" to column headers.
  • Add scope="row" to row headers when rows have named headers.
  • Keep reading order logical in the HTML source.
  • Do not use blank rows or columns merely for visual spacing.
  • Use CSS for presentation.
<table>
  <caption>Quarterly revenue</caption>
  <thead>
    <tr>
      <th scope="col">Quarter</th>
      <th scope="col">Revenue</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">Q1</th>
      <td>$20,000</td>
    </tr>
  </tbody>
</table>

Complex Headers with id and headers Top ↑

For simple tables, scope is usually enough. For a genuinely complex table where a data cell belongs to several headers and the relationship is not clear from scope, the id and headers attributes can make the association explicit.

<table>
  <thead>
    <tr>
      <th id="product">Product</th>
      <th id="price">Price</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td headers="product">Laptop</td>
      <td headers="price">$800</td>
    </tr>
  </tbody>
</table>
Do not add headers attributes to every simple table by habit. Prefer the simplest correct header structure.

Sorting Table Rows with JavaScript Top ↑

Sorting is an application enhancement rather than part of the HTML table element itself. Keep the HTML structure semantic first, then add JavaScript behavior.

This compact example sorts the first <tbody> by a selected column:

<button type="button" onclick="sortTable(0)">Sort by name</button>

<table id="students">
  <thead>
    <tr>
      <th scope="col">Name</th>
      <th scope="col">Age</th>
    </tr>
  </thead>
  <tbody>
    <tr><td>Bob</td><td>30</td></tr>
    <tr><td>Alice</td><td>25</td></tr>
  </tbody>
</table>

<script>
function sortTable(columnIndex) {
  const tbody = document.querySelector("#students tbody");
  const rows = Array.from(tbody.rows);

  rows.sort((a, b) =>
    a.cells[columnIndex].textContent.localeCompare(
      b.cells[columnIndex].textContent
    )
  );

  tbody.append(...rows);
}
</script>
For a production sortable table, also communicate the current sort state to users and support keyboard interaction. A plain clickable <th> is not automatically an accessible control.
<label for="tableSearch">Search names</label>
<input type="search" id="tableSearch">

<script>
const input = document.getElementById("tableSearch");
const rows = document.querySelectorAll("#students tbody tr");

input.addEventListener("input", () => {
  const query = input.value.toLowerCase();

  rows.forEach(row => {
    const match = row.textContent.toLowerCase().includes(query);
    row.hidden = !match;
  });
});
</script>

This filters data rows while leaving the table header intact.

Export Table Data to CSV Top ↑

The original page included a CSV export example. When generating CSV, values containing commas, quotes or line breaks must be quoted correctly.

<button type="button" onclick="exportTableToCSV('table-data.csv')">
  Download CSV
</button>

<script>
function csvCell(value) {
  return '"' + value.replaceAll('"', '""') + '"';
}

function exportTableToCSV(filename) {
  const rows = document.querySelectorAll("#students tr");
  const lines = [];

  rows.forEach(row => {
    const cells = row.querySelectorAll("th, td");
    lines.push(
      Array.from(cells, cell => csvCell(cell.textContent.trim())).join(",")
    );
  });

  const blob = new Blob(
    [lines.join("\r\n")],
    { type: "text/csv;charset=utf-8" }
  );

  const url = URL.createObjectURL(blob);
  const link = document.createElement("a");
  link.href = url;
  link.download = filename;
  link.click();
  URL.revokeObjectURL(url);
}
</script>

For large datasets, export from the server or data source rather than rebuilding a large CSV from the rendered DOM.

Bootstrap Table Styles Top ↑

Plus2net pages use Bootstrap table classes for common presentation patterns.

<table class="table table-striped table-bordered">
  <thead>
    <tr>
      <th scope="col">Name</th>
      <th scope="col">Age</th>
    </tr>
  </thead>
</table>

Bootstrap table design

Table Background Image Top ↑

The existing Plus2net tutorial below covers adding a background image to a table.

Table Background Image

Use background images only when they do not reduce text readability or obscure table data.

Common Table Mistakes Top ↑

Using border="1" for presentation Top ↑

The old border attribute is obsolete for modern styling. Use CSS borders.

Using tables for page layout Top ↑

Use tables for data with row/column relationships. Use CSS Grid, Flexbox or other layout CSS for page structure.

Using td for header cells Top ↑

Use <th> for real row or column headers and identify their scope where appropriate.

Leaving out a useful caption Top ↑

When the table needs a title or explanation, use <caption> so the description is structurally associated with the table.

Adding complex headers attributes to simple tables Top ↑

Simple tables usually need only clear <th> cells and scope. Use id/headers when the header relationships are genuinely complex.

Making wide tables unreadable on mobile Top ↑

Use a horizontal scrolling wrapper or redesign the data presentation rather than shrinking all text until it becomes unreadable.

Making th clickable without real controls Top ↑

If table sorting is interactive, provide keyboard-operable controls and expose sort state appropriately.

Building CSV with plain comma joining Top ↑

CSV values containing commas, quotes or line breaks need proper quoting and quote escaping.

Frequently Asked Questions Top ↑

Q1: Which tags are used to create an HTML table?

Use table for the table, tr for rows, th for header cells and td for data cells. Caption, thead, tbody and tfoot can add more structure.

Q2: Should I use border="1" on an HTML table?

No for modern presentation. Use CSS to add borders, spacing and other visual styles.

Q3: What is the difference between th and td?

th represents a header cell, while td represents a normal data cell.

Q4: What does scope="col" do?

It identifies a th element as the header for a column. scope="row" identifies a row header.

Q5: What is colspan?

colspan makes one table cell span across more than one column.

Q6: How do I make a wide table responsive?

A common approach is to place the table in a wrapper with overflow-x:auto so users can scroll horizontally on smaller screens.

Q7: Should tables be used to create a page layout?

No. Use tables for tabular data and CSS layout tools for page structure.


HTML Meta Tags Paragraph Bold Tag



plus2net.com







veerender

04-10-2012

thank u



We use cookies to improve your browsing experience. . Learn more
HTML MySQL PHP JavaScript ASP Photoshop Articles Contact us
©2000-2026   plus2net.com   All rights reserved worldwide Privacy Policy Disclaimer