Designing Responsive HTML Tables for Webflow Rich Text

A practical look at turning one-off Webflow tables into a maintainable system using semantic HTML, content-led variants, shared CSS, and a clear relationship between Figma, Webflow, and CMS publishing.

Tables tend to look finished before they have been tested.

A border, a header row, and a few evenly spaced columns can make a table feel like a solved component. Then real content arrives. A technical identifier wraps in an awkward place. A descriptive column becomes too narrow to read comfortably. On a phone, the effort to make everything fit begins to damage the information the table was meant to clarify.

I encountered this while working on technical articles for Capte. What began as a small styling problem gradually revealed a more useful systems question: how should a table pattern move between content, design, and production without becoming a collection of one-off fixes?

The answer was not a single, increasingly complicated table. It was a shared foundation with a small number of variants shaped by the information inside them.

The limits of a universal table

The first implementation was reasonable. Article tables shared the same typography, borders, spacing, header treatment, minimum width, and responsive behavior. This gave them a consistent visual language and kept the CSS manageable.

The tension appeared when we began adjusting column widths.

One table listed parts of the SAE J1939 standard alongside their roles. Its first column contained values such as J1939-11 / -15 / -14. These identifiers needed enough space to remain intact. Breaking them across several lines made the table harder to scan and weakened the relationship between the standard and its description.

Another table described layers of vehicle communication. Its first column held labels such as Physical, Data Link, and Transport, while the remaining columns carried longer explanations and failure symptoms. Giving this table the same wide first column left too little room for the content doing most of the explanatory work.

Both tables belonged to the same article system. Both used the same visual treatment. But they did not contain the same kind of information.

That distinction mattered more than their surface similarity.

Begin with what can remain shared

The visual foundation did not need to change. A base class could still define the parts that should remain consistent across every article table:

.article-table {
 width: 100%;
 margin: 2rem 0;
 overflow-x: auto;
 -webkit-overflow-scrolling: touch;
 border: 1px solid #dbe3f4;
 border-radius: 0.75rem;
 background: #fff;
}

.article-table table {
 width: 100%;
 min-width: 42rem;
 border-collapse: collapse;
}

.article-table caption {
 padding: 1rem 1.25rem;
 color: #071533;
 font-weight: 600;
 text-align: left;
}

.article-table th,
.article-table td {
 padding: 0.875rem 1.25rem;
 border-top: 1px solid #dbe3f4;
 text-align: left;
 vertical-align: top;
}

.article-table thead th {
 background: #f2f6ff;
 color: #001c7f;
 font-size: 0.875rem;
}

.article-table tbody th {
 color: #071533;
 font-weight: 600;
}

This base establishes how an article table belongs to the wider interface. It does not decide how every set of columns should behave.

That responsibility belongs to the variant.

Type 1: keeping identifiers intact

The first variant is for identifier-led information: standards, protocol names, model numbers, product codes, or other values that function more like discrete units than sentences.

For this pattern, the first column receives a protected width and resists wrapping:

.article-table.table-type-1 table {
 table-layout: auto;
}

.article-table.table-type-1 th:first-child,
.article-table.table-type-1 td:first-child {
 width: 20rem;
 min-width: 20rem;
 white-space: nowrap;
}

The exact width is adjustable. The important decision is structural: when an identifier is most useful as an intact value, the layout should protect it.

The markup remains semantic and fairly ordinary:

<div class="article-table table-type-1">
 <table>
   <caption>Key SAE J1939 standard parts and their roles</caption>

   <thead>
     <tr>
       <th scope="col">Part</th>
       <th scope="col">Role</th>
     </tr>
   </thead>

   <tbody>
     <tr>
       <th scope="row">J1939-11 / -15 / -14</th>
       <td>Physical layer (250 kbit/s; -14 defines 500 kbit/s)</td>
     </tr>
   </tbody>
 </table>
</div>

There is no article-specific styling in the embed. The content selects a supported pattern; the global system determines how that pattern behaves.

Type 2: making room for explanation

The second variant handles tables in which several columns contain meaningful amounts of prose.

In the communication-layer example, the first column still needed enough room for labels such as 5–7 — Session / Presentation / Application. It simply did not need the same protection as a column of technical identifiers. The two descriptive columns carried more informational weight and needed a larger share of the table.

The resulting distribution was 24% / 38% / 38%:

.article-table.table-type-2 table {
 table-layout: fixed;
}

.article-table.table-type-2 th:first-child,
.article-table.table-type-2 td:first-child {
 width: 24%;
 min-width: 0;
 white-space: normal;
}

.article-table.table-type-2 th:nth-child(2),
.article-table.table-type-2 td:nth-child(2),
.article-table.table-type-2 th:nth-child(3),
.article-table.table-type-2 td:nth-child(3) {
 width: 38%;
 min-width: 0;
 white-space: normal;
}

Here, wrapping is expected. The proportions are not meant to make the table perfectly symmetrical; they reflect where the explanation lives.

This is a small difference in CSS, but a useful difference in intent. Column widths become part of the way the information is communicated.

Name variants by purpose

It would be possible to describe these patterns as a “wide first column” table and a “balanced three-column” table. Those names are visually accurate, but they do not help someone decide when to use them.

In the design system, I prefer names tied to the structure of the content:

  • Identifier for standards, codes, models, and other values that should remain intact.
  • Description Heavy for comparisons, classifications, symptoms, processes, and similar tables in which multiple columns carry explanatory text.

The production classes can remain pragmatic:

.article-table
.table-type-1
.table-type-2

Figma can expose the more human-readable language:

Table / Article
├── Identifier
└── Description Heavy

This creates a modest but important separation. Designers and authors choose a pattern based on meaning. The implementation maps that choice to the appropriate class.

Responsive design should preserve comprehension

Tables often become awkward on small screens because we assume responsiveness means fitting everything inside the viewport.

For dense technical information, that is not always the most useful goal. Columns can only become so narrow before headings fragment, identifiers become difficult to parse, and comparisons lose their horizontal relationship.

In this system, the wrapper scrolls horizontally while the table maintains a minimum usable width:

.article-table {
 overflow-x: auto;
 -webkit-overflow-scrolling: touch;
}

.article-table table {
 min-width: 42rem;
}

The page remains responsive, but the table does not pretend that a complex comparison can always be compressed into a narrow column of stacked fragments.

Horizontal scrolling introduces a tradeoff. It is less immediately visible than a fully stacked layout. But in this case it preserves the relationships the table was created to show. That is the more important form of responsiveness.

Semantic HTML belongs to the component

The visual pattern is only part of the system. A table also needs a dependable semantic structure:

<table>
 <caption>...</caption>

 <thead>
   <tr>
     <th scope="col">...</th>
   </tr>
 </thead>

 <tbody>
   <tr>
     <th scope="row">...</th>
     <td>...</td>
   </tr>
 </tbody>
</table>

The caption tells readers what the table represents. Column headers identify the fields being compared. Row headers establish the subject of each record. These relationships help assistive technology interpret the table, but they also encourage better content structure at the point of authoring.

For that reason, the expected HTML should be documented alongside spacing, color, and border treatment. A component definition that stops at appearance leaves part of the experience unspecified.

Let Figma and Webflow carry different responsibilities

Once the table became a repeatable pattern, the next question was where it should live.

The practical answer was both Figma and Webflow, with a clear division of responsibility.

Figma documents the design contract:

  • Anatomy
  • Visual tokens
  • Supported variants
  • Column relationships
  • Examples and usage guidance
  • Expected responsive intent

Webflow owns the production behavior:

  • Global CSS
  • Semantic HTML
  • Minimum widths and overflow
  • Exact column sizing
  • CMS publishing

Figma does not need to reproduce browser table behavior perfectly. Its job is to make the pattern understandable and selectable. Webflow does not need to carry all of the explanatory documentation inside the page. Its job is to render the system reliably.

The relationship is simple:

Figma specifies. Webflow implements. CMS content consumes.

That is more useful than trying to make the two tools mirror one another at every level.

Give the production system somewhere to be tested

Global CSS is efficient, but a change to it can affect every table already published. A small internal Table Lab in Webflow gives the system a stable place to be reviewed.

The page can contain canonical examples of each supported type, along with stress tests for long identifiers, long headings, dense descriptions, and narrow viewports. When the CSS changes, the table system can be checked in one place rather than rediscovered across several articles.

This also makes publishing behavior easier to separate from content behavior. The global styles can be confirmed first, then the CMS item can be checked with greater confidence.

For a component that lives inside rich text rather than the Webflow Designer’s usual component model, this kind of test page becomes its production counterpart.

Allow the system to grow from evidence

There is a temptation, once a pattern becomes part of a design system, to anticipate every possible variation. That tends to produce more options than anyone can explain or maintain.

These tables suggest a narrower rule:

New content does not automatically require a new table type. A meaningfully different information structure might.

A future property-and-value table could justify its own pattern if it consistently behaves differently from Identifier and Description Heavy. A request to make one column slightly wider in a single article probably does not.

This keeps the system responsive to real use without turning it into a catalog of exceptions. Each addition should resolve a recurring structural need and remain useful beyond the page that revealed it.

The component follows the content

The useful outcome of this work is not really two table variants. It is a clearer relationship between content and the system around it.

Real information exposed where the universal component stopped working. That led to a small extension rather than an isolated fix. Figma now explains the intent, Webflow carries the behavior, semantic markup preserves the relationships, and CMS authors can use the pattern without restyling it each time.

The same approach can extend beyond tables. Technical content includes diagrams, specifications, callouts, procedures, metadata, and code. These elements need a shared visual language, but they do not always need identical behavior.

A durable design system leaves enough room for those differences. It provides consistency without asking the information to become simpler than it is.

In that sense, the table is doing what a good component should do: giving the content structure, then getting out of its way.

September 3, 2026