HTML colgroup and col
HTML tables are built row by row. There is no "column" element holding the cells of column 3. That is simple to write, but it raises a question: what if you want to color a whole column, or set one column's width, without adding a class to every cell in it?
HTML has an answer. Two small elements, <colgroup> and <col>, let you describe the table's columns separately, so you can style them in one go. They hold no content. They only describe the grid. In this lesson, you will learn how they work, what they can (and cannot) style, and when they are worth using.
What You Will Learnβ
- What
<colgroup>and<col>are for - Where they go in a table
- How to use the
spanattribute - How to set column widths and fixed layouts
- Which CSS properties work on columns
- How to highlight a column, and group columns
- What columns do (and do not do) for accessibility
The Problem They Solveβ
Suppose you want the "Price" column in a table to have a light yellow background. Without column elements, you would add a class to every cell in that column:
<tr>
<td>Notebook</td>
<td class="price">3.50</td>
</tr>
<tr>
<td>Pen set</td>
<td class="price">16.25</td>
</tr>
<!-- ...and so on for every row -->
That is a lot of repetition, and it is easy to forget a cell. With <col>, you describe the column once.
The Basicsβ
| Element | Name | Job |
|---|---|---|
<colgroup> | Column group | A container that groups one or more column descriptions |
<col> | Column | Describes one column (or several, with span). It is a void element: no content and no closing tag |
- HTML + CSS
- Browser Output
col.price {
background: #fef9c3;
}
<table>
<colgroup>
<col /> <!-- column 1: no special style -->
<col class="price" /> <!-- column 2: yellow background -->
<col /> <!-- column 3 -->
</colgroup>
<tr>
<th>Item</th>
<th>Price</th>
<th>Stock</th>
</tr>
<tr>
<td>Notebook</td>
<td>3.50</td>
<td>40</td>
</tr>
<tr>
<td>Pen set</td>
<td>16.25</td>
<td>12</td>
</tr>
</table>
| Item | Price | Stock |
|---|---|---|
| Notebook | 3.50 | 40 |
| Pen set | 16.25 | 12 |
The second <col> describes the second column, and the style applies to every cell in it. (In the live demo, the Price cells are set to a transparent background, so the column color shows through. A cell's own background is painted on top of the column's.)
Each <col> describes one column, in order, left to right.
Where They Goβ
<colgroup> is placed inside <table>:
- After
<caption>(if there is one) - Before
<thead>,<tbody>,<tfoot>, and any<tr>
<table>
<caption>Inventory</caption>
<colgroup>
<col />
<col />
</colgroup>
<thead>...</thead>
<tbody>...</tbody>
</table>
| Rule | Details |
|---|---|
| Position | After <caption>, before the row sections |
<col> placement | Inside a <colgroup>, or directly as <col> with no wrapper is not valid. Always wrap it |
| Content | <colgroup> contains only <col> (or nothing, if you use span) |
| Count | A table may have several <colgroup> elements |
If your table has a caption, it is always first. Then <colgroup>. Then the header, body, and footer.
The span Attributeβ
When several neighboring columns share the same style, don't repeat <col>. Use span.
On <col>β
<colgroup>
<col /> <!-- column 1 -->
<col span="2" class="data" /> <!-- columns 2 and 3 -->
</colgroup>
On <colgroup>β
When a <colgroup> has no <col> children, span tells it how many columns it covers.
<colgroup span="2" class="info"></colgroup>
<colgroup span="3" class="scores"></colgroup>
This table has five columns: the first two form a group called "info," and the next three form a group called "scores."
| Where | span means | Note |
|---|---|---|
<col span="3"> | This one <col> covers 3 columns | A whole-number value of 1 or more |
<colgroup span="3"> | The group covers 3 columns | Use only if the group has no <col> children |
If a <colgroup> contains <col> elements, its own span is ignored. Choose one method per group.
Setting Column Widthsβ
One of the most useful jobs for <col> is controlling widths.
table {
table-layout: fixed; /* widths come from the first row and the col elements */
width: 100%;
}
- HTML + CSS
- Browser Output
<table style="table-layout: fixed; width: 100%;">
<colgroup>
<col style="width: 50%;" />
<col style="width: 25%;" />
<col style="width: 25%;" />
</colgroup>
<tr>
<th>Description</th>
<th>Qty</th>
<th>Price</th>
</tr>
<tr>
<td>A long description of a product</td>
<td>3</td>
<td>3.50</td>
</tr>
</table>
| Description | Qty | Price |
|---|---|---|
| A long description of a product | 3 | 3.50 |
Here, the first column always takes half the table, and the others take a quarter each, however long the content is. This is called a fixed table layout, and it has a nice bonus: the browser can draw the table faster, because it does not have to measure all the content first.
table-layout | How widths are decided |
|---|---|
auto (default) | By the content. Columns grow to fit |
fixed | By the table width and the first row or <col> widths. Content wraps or is cut off |
Percent widths adapt to the container. Fixed units like rem keep a column steady. In both cases, make sure the widths add up (or leave one column to take the rest).
What CSS Works on Columns?β
This is the part that surprises people. Columns are not like normal boxes. Only four CSS properties have an effect on <col> and <colgroup>:
| Property | What it does | Notes |
|---|---|---|
background | Colors the column | Painted under the cells' own backgrounds |
border | Draws lines around the column | Works with border-collapse: collapse |
width | Sets the column width | The most common use |
visibility | collapse hides the column | Browser support is uneven |
Everything else, such as color, font-weight, text-align, and padding, does not affect the cells in the column.
- Does not work
- Works
col.price {
text-align: right; /* ignored */
font-weight: bold; /* ignored */
color: #166534; /* ignored */
}
col.price {
background: #dcfce7;
border-left: 2px solid #166534;
width: 8rem;
}
To change text properties for a whole column, use a class on the cells, or the CSS :nth-child() selector:
td:nth-child(2),
th:nth-child(2) {
text-align: right;
}
Cells are not inside a column in the document tree. They are inside rows. So a column cannot pass things like text color down to its cells. It can only paint a background behind them, set a width, and draw borders.
Highlighting Columnsβ
A common use is to separate groups of columns, or to call attention to one.
- HTML + CSS
- Browser Output
table {
border-collapse: collapse;
}
col.highlight {
background: #fef9c3;
}
colgroup + colgroup {
border-left: 3px solid #0f172a;
}
<table>
<colgroup>
<col />
</colgroup>
<colgroup>
<col />
<col class="highlight" />
</colgroup>
<tr>
<th>Plan</th>
<th>Basic</th>
<th>Pro</th>
</tr>
<tr>
<td>Projects</td>
<td>3</td>
<td>Unlimited</td>
</tr>
<tr>
<td>Support</td>
<td>Email</td>
<td>Phone and email</td>
</tr>
</table>
| Plan | Basic | Pro |
|---|---|---|
| Projects | 3 | Unlimited |
| Support | Phone and email |
Highlighting the recommended plan is a classic pricing-table trick. The yellow comes from one <col>, and the dark line marks the start of the plan columns.
A highlighted column draws the eye, but it does not carry meaning for screen reader users. If "Pro" is the recommended plan, say so in text too, such as "Pro (recommended)."
Columns and Merged Cellsβ
<col> elements describe grid columns, counted from the left, whatever the cells do. If a cell uses colspan, it covers several grid columns, and each of those columns still has its own <col>.
<colgroup>
<col />
<col class="q1" />
<col class="q1" />
</colgroup>
<tr>
<th>Name</th>
<th colspan="2">Q1</th> <!-- covers columns 2 and 3 -->
</tr>
So a column highlight remains under the "Q1" heading, no matter how it is merged. You learned merging in Colspan and Rowspan.
Accessibility: What Columns Do (and Do Not) Doβ
It is tempting to think <colgroup> also tells screen readers which columns belong together. For the most part, it does not.
| Question | Answer |
|---|---|
Do screen readers announce <col> or <colgroup>? | Generally no. They are mainly for presentation |
| How do I label a group of columns for assistive technology? | Use <th scope="colgroup"> over the group (see Table Headings) |
Can <colgroup> replace <th>? | No. It never labels data |
| Is it harmful to use? | No. It is harmless, and useful for layout |
<th> and scope carry meaning. <colgroup> and <col> carry style. A good table often has both.
Obsolete Attributes to Avoidβ
Older HTML gave <col> and <colgroup> several presentation attributes. They are obsolete. Use CSS.
| Old attribute | Use instead |
|---|---|
width | CSS width |
align | CSS text-align on cells |
valign | CSS vertical-align on cells |
char, charoff | Not supported. Use CSS or formatting in the data |
bgcolor | CSS background |
Only span remains a real, current attribute.
When Are Column Elements Worth Using?β
| Good fit | Poor fit |
|---|---|
| Setting column widths in one place | Tables with only one or two simple columns |
| Highlighting a column or column group | When you need to change text color or alignment (use cell classes) |
| Separating groups of columns | When styling can be done with :nth-child more simply |
| Fixed-layout tables that render quickly | Tables whose structure changes by JavaScript |
Many modern tables skip <colgroup> and use :nth-child or classes. Both are fine. The <col> approach is tidy when the widths matter, because it keeps them in the markup, separate from the data rows.
Putting It Together: A Pricing Tableβ
- HTML Code
- Browser Output
<table class="pricing">
<caption>Plans and prices (USD per month)</caption>
<colgroup>
<col class="feature" />
<col />
<col class="recommended" />
<col />
</colgroup>
<thead>
<tr>
<td></td>
<th scope="col">Free</th>
<th scope="col">Pro (recommended)</th>
<th scope="col">Team</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Price</th>
<td>0</td>
<td>9</td>
<td>29</td>
</tr>
<tr>
<th scope="row">Projects</th>
<td>3</td>
<td>Unlimited</td>
<td>Unlimited</td>
</tr>
</tbody>
</table>
| Free | Pro (recommended) | Team | |
|---|---|---|---|
| Price | 0 | 9 | 29 |
| Projects | 3 | Unlimited | Unlimited |
The text "(recommended)" is in the heading itself, so the highlight is never the only clue.
Global Audience Notesβ
- Right-to-left pages reverse the order of columns when
dir="rtl".<col>elements follow the same order, so the first<col>always matches the first column visually, on the right. - Allow room for translation. Text in some languages is much longer than English. Avoid fixed widths that are too narrow, or use percentages with room to spare.
- Don't encode meaning in color only. Pair highlights with words or symbols.
Common Mistakes to Avoidβ
- Placing
<colgroup>after<thead>or rows. It must come before them. - Putting
<col>outside a<colgroup>. - Expecting
text-alignorcoloron<col>to work. Onlybackground,border,width, andvisibilitydo. - Giving a
<colgroup>bothspanand<col>children. Use only one. - Writing too few or too many
<col>elements. They should match the table's columns. - Closing
<col>with</col>. It is a void element. - Using obsolete attributes such as
widthoralignon<col>. - Relying on
<colgroup>to label columns for screen readers. Use<th scope>. - Setting widths that add up to more than 100% in a fixed table.
- Forgetting
border-collapse: collapsewhen you expect column borders to show cleanly.
Practice Timeβ
Try these in your editor:
- Add a
<colgroup>with three<col>elements to a three-column table. - Give the middle column a light background using a class on its
<col>. - Use
span="2"to style two neighboring columns at once. - Set
table-layout: fixedand give each<col>a percentage width. - Create two
<colgroup>elements and add a border between them. - Try
text-align: righton a<col>, and observe that it does nothing. - Achieve right-aligned numbers instead with
td:nth-child(2). - Highlight the "recommended" column in a pricing table, and also say so in the heading.
- Make sure the
<colgroup>sits after the<caption>and before<thead>. - Bonus: use developer tools to see how the browser maps each
<col>to a column.
Quick Recapβ
Click a question to check your answer.
1. What are <colgroup> and <col> for?
They describe the table's columns, so you can style or size whole columns at once without adding classes to every cell.
2. Where does <colgroup> go?
Inside <table>, after <caption> (if any) and before <thead>, <tbody>, <tfoot>, or rows. <col> elements go inside it.
3. What does span do?
It makes one <col> (or a <colgroup> with no <col> children) cover several columns.
4. Which CSS properties work on columns?
background, border, width, and visibility. Text properties such as color and text-align do not work.
5. Do <colgroup> and <col> help screen readers understand column groups?
Generally no. They are presentational. To label a group of columns for assistive technology, use <th scope="colgroup">.
Key Takeawaysβ
<colgroup>and<col>describe columns, so you can style them without touching every cell.- Put
<colgroup>right after<caption>and before the row sections.<col>is a void element. - Use
spanfor neighboring columns that share a style. - Only
background,border,width, andvisibilitywork on columns. Use:nth-childor classes for the rest. - Columns carry style, not meaning. Use
<th>andscopeto label columns for accessibility.
You can now structure, label, merge, and size a table. It is time to make it look good. Continue with Styling Tables, or return to the [Tables overview]/tutorials(/html/tables).