Column Grouping

Groups related columns.

Order summary
Customer Shipping Method Total
Address City
A. Whitfield14 Elm RdLeedsCourier£64.00
R. Okafor9 Quay StBristolPost£128.50
M. Iqbal2 Mill LnLeicesterCourier£22.00
S. Novak51 Bank StYorkPost£40.00

html

<div class="cgrp" style="--accent:#241430;">
  <div class="cgrp__scroll">
    <table class="cgrp__table">
      <caption>Order summary</caption>
      <thead>
        <tr>
          <th scope="col" rowspan="2">Customer</th>
          <th scope="colgroup" colspan="2" class="cgrp__group">Shipping</th>
          <th scope="col" rowspan="2">Method</th>
          <th scope="col" rowspan="2">Total</th>
        </tr>
        <tr class="cgrp__sub">
          <th scope="col" class="cgrp__subcell">Address</th>
          <th scope="col" class="cgrp__subcell">City</th>
        </tr>
      </thead>
      <tbody>
        <tr><td>A. Whitfield</td><td class="cgrp__subcell">14 Elm Rd</td><td class="cgrp__subcell">Leeds</td><td>Courier</td><td>£64.00</td></tr>
        <tr><td>R. Okafor</td><td class="cgrp__subcell">9 Quay St</td><td class="cgrp__subcell">Bristol</td><td>Post</td><td>£128.50</td></tr>
        <tr><td>M. Iqbal</td><td class="cgrp__subcell">2 Mill Ln</td><td class="cgrp__subcell">Leicester</td><td>Courier</td><td>£22.00</td></tr>
        <tr><td>S. Novak</td><td class="cgrp__subcell">51 Bank St</td><td class="cgrp__subcell">York</td><td>Post</td><td>£40.00</td></tr>
      </tbody>
    </table>
  </div>
</div>
<style>
.cgrp { font: 14px system-ui, sans-serif; color: #241430; background: #FAF7F2; max-width: 480px; border: 1px solid #24143020; border-radius: 10px; overflow: hidden; }
.cgrp__scroll { overflow-x: auto; }
.cgrp__table { border-collapse: collapse; width: 100%; }
.cgrp__table caption { text-align: left; font-weight: 600; padding: 10px 14px; }
.cgrp__table th, .cgrp__table td { padding: 8px 12px; text-align: left; border-bottom: 1px solid #24143020; white-space: nowrap; }
.cgrp__group { background: var(--accent); color: #FAF7F2; text-align: center; }
.cgrp__sub th { background: #24143012; font-size: 12px; }
.cgrp__sub--hidden { display: none; }
.cgrp--collapsed .cgrp__subcell { max-width: 44px; overflow: hidden; text-overflow: ellipsis; }
</style>

tailwind

<div class="max-w-[480px] rounded-[10px] border border-[#24143020] font-sans text-sm text-[#241430] bg-[#FAF7F2] overflow-hidden" style="--accent:#241430;">
  <div class="overflow-x-auto">
    <table class="border-collapse w-full">
      <caption class="text-left font-semibold px-3.5 py-2.5">Order summary</caption>
      <thead>
        <tr>
          <th scope="col" rowspan="2" class="p-2 text-left border-b border-[#24143020] whitespace-nowrap">Customer</th>
          <th scope="colgroup" colspan="2" class="p-2 text-center text-[#FAF7F2]" style="background:#241430">Shipping</th>
          <th scope="col" rowspan="2" class="p-2 text-left border-b border-[#24143020] whitespace-nowrap">Method</th>
          <th scope="col" rowspan="2" class="p-2 text-left border-b border-[#24143020] whitespace-nowrap">Total</th>
        </tr>
        <tr class="">
          <th scope="col" class="cgrp__subcell p-2 text-left bg-[#24143012] text-xs border-b border-[#24143020]">Address</th>
          <th scope="col" class="cgrp__subcell p-2 text-left bg-[#24143012] text-xs border-b border-[#24143020]">City</th>
        </tr>
      </thead>
      <tbody>
        <tr><td class="p-2 border-b border-[#24143020] whitespace-nowrap">A. Whitfield</td><td class="cgrp__subcell p-2 border-b border-[#24143020] whitespace-nowrap">14 Elm Rd</td><td class="cgrp__subcell p-2 border-b border-[#24143020] whitespace-nowrap">Leeds</td><td class="p-2 border-b border-[#24143020] whitespace-nowrap">Courier</td><td class="p-2 border-b border-[#24143020] whitespace-nowrap">£64.00</td></tr>
        <tr><td class="p-2 border-b border-[#24143020] whitespace-nowrap">R. Okafor</td><td class="cgrp__subcell p-2 border-b border-[#24143020] whitespace-nowrap">9 Quay St</td><td class="cgrp__subcell p-2 border-b border-[#24143020] whitespace-nowrap">Bristol</td><td class="p-2 border-b border-[#24143020] whitespace-nowrap">Post</td><td class="p-2 border-b border-[#24143020] whitespace-nowrap">£128.50</td></tr>
        <tr><td class="p-2 border-b border-[#24143020] whitespace-nowrap">M. Iqbal</td><td class="cgrp__subcell p-2 border-b border-[#24143020] whitespace-nowrap">2 Mill Ln</td><td class="cgrp__subcell p-2 border-b border-[#24143020] whitespace-nowrap">Leicester</td><td class="p-2 border-b border-[#24143020] whitespace-nowrap">Courier</td><td class="p-2 border-b border-[#24143020] whitespace-nowrap">£22.00</td></tr>
        <tr><td class="p-2 border-b border-[#24143020] whitespace-nowrap">S. Novak</td><td class="cgrp__subcell p-2 border-b border-[#24143020] whitespace-nowrap">51 Bank St</td><td class="cgrp__subcell p-2 border-b border-[#24143020] whitespace-nowrap">York</td><td class="p-2 border-b border-[#24143020] whitespace-nowrap">Post</td><td class="p-2 border-b border-[#24143020] whitespace-nowrap">£40.00</td></tr>
      </tbody>
    </table>
  </div>
</div>

react

function ColumnGrouping({
  caption = "Order summary",
  accent = "#241430",
  groupLabel = "Shipping",
  showSubheaders = true,
  collapsedGroup = false,
}) {
  const rows = [
    ["A. Whitfield", "14 Elm Rd", "Leeds", "Courier", "£64.00"],
    ["R. Okafor", "9 Quay St", "Bristol", "Post", "£128.50"],
    ["M. Iqbal", "2 Mill Ln", "Leicester", "Courier", "£22.00"],
    ["S. Novak", "51 Bank St", "York", "Post", "£40.00"],
  ];
  const cell = { padding: "8px 12px", borderBottom: "1px solid #24143020", whiteSpace: "nowrap" };
  const subCell = collapsedGroup ? { ...cell, maxWidth: 44, overflow: "hidden", textOverflow: "ellipsis" } : cell;
  return (
    <div style={{ maxWidth: 480, borderRadius: 10, border: "1px solid #24143020", overflow: "hidden", font: "14px system-ui, sans-serif", color: "#241430", background: "#FAF7F2" }}>
      <div style={{ overflowX: "auto" }}>
        <table style={{ borderCollapse: "collapse", width: "100%" }}>
          <caption style={{ textAlign: "left", fontWeight: 600, padding: "10px 14px" }}>{caption}</caption>
          <thead>
            <tr>
              <th scope="col" rowSpan={2} style={cell}>Customer</th>
              <th scope="colgroup" colSpan={2} style={{ ...cell, background: accent, color: "#FAF7F2", textAlign: "center" }}>{groupLabel}</th>
              <th scope="col" rowSpan={2} style={cell}>Method</th>
              <th scope="col" rowSpan={2} style={cell}>Total</th>
            </tr>
            {showSubheaders && (
              <tr>
                <th scope="col" style={{ ...cell, background: "#24143012", fontSize: 12 }}>Address</th>
                <th scope="col" style={{ ...cell, background: "#24143012", fontSize: 12 }}>City</th>
              </tr>
            )}
          </thead>
          <tbody>
            {rows.map((r) => (
              <tr key={r[0]}>
                <td style={cell}>{r[0]}</td>
                <td style={subCell}>{r[1]}</td>
                <td style={subCell}>{r[2]}</td>
                <td style={cell}>{r[3]}</td>
                <td style={cell}>{r[4]}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
}