HTML Table Borders and Spacing
By default, an HTML table renders with no visible borders and very little space between its cells — it looks almost like plain text arranged in a grid. For decades, authors controlled the look of a table’s borders and internal spacing using three HTML attributes: border, cellpadding, and cellspacing. Understanding these attributes matters even today, because you will still encounter them in older code, in email templates (which still rely on table-based layout), and in browser default behavior that CSS later took over.
Overview: How Table Rendering Works
When a browser parses a <table> element, it builds an internal table box model made up of nested boxes: the table wrapper, optional <caption>, row groups (<thead>, <tbody>, <tfoot>), rows (<tr>), and cells (<th>, <td>). Each of these is a real box in the rendering tree, even though most of them have no default border or background.
Historically, three things controlled the visual gaps and lines in that grid:
border — a numeric attribute on <table> that draws a border around the table and, in most browsers, around each cell too, using a beveled 3D-style line whose thickness (in pixels) is given by the number.
cellpadding — the space, in pixels, between a cell’s border and its content (similar in effect to CSS padding on table cells).
cellspacing — the space, in pixels, between adjacent cells, and between cells and the outer table border (similar in effect to the CSS property border-spacing).
These three attributes are part of HTML’s presentational history. In the HTML5 specification they are formally obsolete (not removed from browsers for backward compatibility, but no longer recommended for authors to use). Modern practice separates structure from presentation: HTML defines the table’s rows, columns, and headers; CSS defines how it looks, including borders, spacing, and collapsing behavior. This lesson explains both the legacy attributes (so you can read and understand old markup) and how tables render without them, since you will encounter both in the wild.
Syntax
<table border="1" cellpadding="4" cellspacing="2">
<tr>
<th>Header</th>
</tr>
<tr>
<td>Cell</td>
</tr>
</table>
| Attribute | Applies to | Effect |
|---|---|---|
border |
<table> |
Numeric pixel value; draws a border around the table and cells. border="0" means no border. |
cellpadding |
<table> |
Numeric pixel value; space between a cell’s edge and its content. |
cellspacing |
<table> |
Numeric pixel value; space between cells, and between cells and the table edge. |
Note that all three attributes are set on the <table> element itself — there is no per-cell version of cellpadding or cellspacing in HTML. If you need different padding for individual cells, that requires CSS.
Examples
Example 1: A table with no styling attributes
<table>
<tr>
<th>Name</th>
<th>Score</th>
</tr>
<tr>
<td>Amara</td>
<td>92</td>
</tr>
<tr>
<td>Devon</td>
<td>88</td>
</tr>
</table>
Result: The browser renders a 2-column, 3-row grid with bold, centered header text (“Name”, “Score”) in the first row, but with no visible lines around the cells and only minimal default spacing between the text in each cell. Visually, it looks like loosely aligned columns of text rather than a “table” with a grid, because no border has been requested anywhere.
This is important to internalize: tables have no border by default. Many beginners are surprised the first time they build a table and see no grid lines at all.
Example 2: Adding a border with the legacy attribute
<table border="1">
<tr>
<th>Name</th>
<th>Score</th>
</tr>
<tr>
<td>Amara</td>
<td>92</td>
</tr>
<tr>
<td>Devon</td>
<td>88</td>
</tr>
</table>
Result: The same 2-column, 3-row grid now appears with a visible border around the outside of the table and around every individual cell, typically rendered with a subtle inset/beveled 3D look in most browsers (a light edge on one side, a darker edge on the other). The number 1 sets the border thickness in pixels.
Because border also implicitly borders every cell (not only the table’s outer edge), a single attribute is enough to turn a plain grid of text into something that visually reads as a table.
Example 3: Combining border, cellpadding, and cellspacing
<table border="1" cellpadding="8" cellspacing="4">
<tr>
<th>Product</th>
<th>Price</th>
</tr>
<tr>
<td>Notebook</td>
<td>$3.50</td>
</tr>
<tr>
<td>Pen</td>
<td>$1.20</td>
</tr>
</table>
Result: The table renders noticeably larger and airier than Example 2. Each cell has its border visible (from border="1"), but now there is an 8-pixel gap between the text and each cell’s inner edge (from cellpadding), and a 4-pixel gap of visible table background between neighboring cells and around the outer edge (from cellspacing). Instead of a tight grid, the cells look like separate little boxes floating with small gaps between them, since cellspacing pushes the individual cell borders apart rather than merging them into shared grid lines.
This “separated boxes” look is a direct visual side effect of cellspacing: because it inserts space between cells, each cell keeps its own complete border rather than sharing a border line with its neighbor.
Under the Hood: How the Browser Builds This
When the parser encounters <table>, it constructs an internal table formatting context. Conceptually, the browser treats the table as a grid of rectangular cell boxes laid out in rows and columns. The border attribute is translated by the browser’s default (user-agent) stylesheet into an actual CSS border on the table and, historically, a matching border on every cell — this is why border="1" outlines cells even though you never touched CSS. Similarly, cellpadding maps roughly to padding inside each <td>/<th>, and cellspacing maps roughly to the CSS border-spacing property applied to the table, which controls the gap between adjacent cell boxes.
This is exactly why these attributes are obsolete rather than functionally removed: their effects are just presentational shortcuts for underlying CSS concepts (border, padding, border-spacing, and border-collapse). Once CSS matured, there was no longer a need to bake presentation into the HTML attributes themselves — the same visual results, and far more control, are available through CSS rules targeting table, th, and td selectors. That styling work belongs in a CSS stylesheet, which is covered in this site’s CSS course, not in the HTML markup itself.
Common Mistakes
Mistake 1: Assuming a table has a visible grid by default
<table>
<tr><td>A</td><td>B</td></tr>
</table>
Beginners often write plain <table> markup and expect visible lines to appear automatically. Without border (or CSS borders), the browser renders no lines at all, only the raw text laid out in a grid shape. The fix is to either add a border attribute for a quick legacy result, or, preferably, apply CSS borders to the table and its cells.
Mistake 2: Using cellpadding/cellspacing as a substitute for real layout spacing
<table cellpadding="20" cellspacing="20">
<tr><td>Sidebar content</td><td>Main content</td></tr>
</table>
This pattern comes from an era when tables were used for whole-page layout (splitting a page into columns using table cells). It’s a mistake today because layout spacing is a visual/structural design concern that belongs to CSS (margin, padding, gap, grid, flexbox), not to a data table’s markup. Using a <table> purely to space out unrelated page sections also misleads assistive technology, which will announce it as tabular data. The corrected approach uses semantic layout elements styled with CSS instead of a table:
<div class="layout">
<aside>Sidebar content</aside>
<main>Main content</main>
</div>
Mistake 3: Forgetting that cellspacing separates cell borders
Authors who want one clean unified grid (each internal line shared between two adjacent cells) sometimes add cellspacing="5" expecting nicer spacing, then are confused when every cell shows its own separate border instead of a single shared grid line. That doubled-border look is cellspacing doing exactly what it’s meant to do — separating the cell boxes. To get a single, shared-line grid instead, the modern fix is the CSS property border-collapse: collapse, which has no HTML attribute equivalent at all — another reason CSS replaced these attributes rather than extending them.
Best Practices
- Prefer CSS over
border,cellpadding, andcellspacingin new markup — they are obsolete in HTML5, even though browsers still render them for backward compatibility. - If you must support very old email clients or legacy renderers that ignore embedded CSS, the legacy attributes can still serve as a functional fallback, but treat this as an exception, not the default approach.
- Keep HTML focused on structure: rows, columns, headers, and captions. Leave borders, spacing, and colors to CSS, where properties like
border,padding,border-spacing, andborder-collapsegive far more precise control. - Never use a table (or its spacing attributes) purely to add whitespace around unrelated page content — that is a layout job, not a data-table job, and it confuses screen readers.
- When reading old codebases, recognize
border="1",cellpadding, andcellspacingon sight so you can understand (and safely modernize) legacy table markup.
Practice Exercises
Exercise 1: Build a 3-column, 2-row table of your own choosing (e.g. fruit, color, price) with no border attributes at all. Predict, then check, what it looks like with no lines.
Exercise 2: Take your table from Exercise 1 and add border="1". Notice which edges gain lines that weren’t there before.
Exercise 3: Add cellpadding="10" and cellspacing="6" to the same table and describe, in your own words, the difference between what padding changed versus what spacing changed.
Summary
- HTML tables have no visible border or extra spacing by default — the browser only lays out the grid structure.
- The legacy
borderattribute on<table>adds a numeric-pixel border around the table and its cells. cellpaddingcontrols space between a cell’s content and its own border;cellspacingcontrols space between separate cells.- All three attributes are obsolete in HTML5 — still rendered by browsers, but replaced by CSS properties (
border,padding,border-spacing,border-collapse) in modern practice. - Use HTML for the table’s structure and semantics; use CSS for how it looks, including borders and spacing.
