Design for the Field Type, Not the Field Name
Most profile screens, product specs and detail pages are built the same way. Someone lists the fields the design needs, and the template renders them by name: work experience here, education below it, links in the sidebar. It ships, it looks right, and it is quietly the wrong shape.
The problem shows up the first time somebody adds a field the template has never heard of. A new “Certifications” group, a “Portfolio” section, a “Research interests” list. The layout has no case for it, so it falls through to a generic renderer and looks like a slightly broken version of everything around it. The considered sections were the ones the designer happened to imagine. Everything else is second class.
The fix is a small change in what the layout keys off. Stop rendering by field name. Render by field type.
What that changes
In a name-driven layout, the template contains a branch per known section. Work Experience gets timeline entries. Education gets timeline entries. Skills get chips. Everything else gets a label and a value on one line.
In a type-driven layout, the template contains a branch per kind of value, and the field’s declared type decides which branch it lands in:
| Field type | How it renders |
|---|---|
| Paragraph / long text | Full paragraphs, readable measure, not squeezed onto one line |
| Multi-select / list | A row of small chips |
| URL | A clickable link, labelled by where it points |
| Text, date, number, boolean, single choice | One labelled line, label left, value right |
| Repeater group | Entry cards: bold heading, quiet supporting line, collapsed date range, description |
Nobody picks a presentation. The person building the field picks a type, because they had to pick one anyway, and the presentation follows from it.
The consequence is the whole point: a custom “Certifications” repeater that nobody designed for gets the same entry cards as the built-in work history. A “Portfolio” group with a description and two links gets the same treatment as any shipped section. There is no special case to add, no code to write, and no waiting for the design system to grow a branch for your particular idea.
The difference is easiest to see side by side:
| Name-driven | Type-driven | |
|---|---|---|
| Template branches | One per known section, grows forever | One per value kind, five or six total |
| A field nobody designed for | Falls through to a generic renderer | Renders like everything else |
| Adding a content type | A design ticket | No work |
| Risk of visual drift | High. Similar sections built at different times | None. There is only one chip row |
| Responsive and RTL testing | Every section, every breakpoint | Every value kind, once |
| Bespoke editorial layouts | Straightforward | Fights the model |
Why this is a design decision, not an engineering one
It is tempting to file this under implementation detail. It is not, because it changes what the design system is promising.
A name-driven layout promises: these sections look good. A type-driven layout promises: anything of this shape looks good. The second is a much larger promise and a much smaller amount of work, and it moves the design effort to the right place.
Under the first model, every new content type is a design ticket. Under the second, the design tickets are about the five or six value kinds, and you spend real time on them because each one now serves an unbounded number of fields. Getting the chip row right once is worth more than getting Skills right, because chips are now how every list of short things renders forever.
This also fixes a chronic drift problem. Name-driven layouts accumulate near-duplicates: the Skills chips and the Interests chips get built at different times by different people and end up two pixels and one border-radius apart. When both are the multi-select branch, they cannot drift, because there is only one of them.
The rules that make it hold up
Four things have to be true or the pattern degrades back into special cases.
Field types must be a closed, small set. If anyone can invent a type, you are back to a branch per name with extra steps. Five to eight is the right order of magnitude. If a new content need genuinely does not fit any of them, that is a real signal worth a design conversation, not a reason to add a one-off.
Empty must be a state you designed. A section with nothing in it should hide itself, and if there is nothing at all, the surface should not appear. This matters more here than in a name-driven layout, because you no longer control which combinations occur. A new profile has to look clean rather than look broken, and the only way that happens reliably is if empty is handled at the type level rather than per section.
Ordering belongs to configuration, not to the template. Once the template no longer knows section names, it also has no opinion about their order. Whoever configures the fields arranges the groups, and the layout follows. That is a feature, but only if the configuration surface actually offers ordering.
Permissions filter before layout, not during. If a field is restricted to some viewers, it should be removed from the data before the page is built rather than hidden with CSS. Two reasons: the obvious one is that hidden markup is not private, and the less obvious one is that a filtered-out field must not leave a gap. If the layout receives only what this viewer may see, the empty-state rule above handles the rest automatically. A logged-out visitor, a follower and the owner should each get a page that looks deliberate rather than a page with holes in it.
How to migrate a layout you already shipped
You almost certainly have a name-driven layout in production. Replacing it wholesale is rarely worth it, and it is not necessary, because the two models coexist perfectly well during a transition.
Start by cataloguing what you render, not what you have. Walk the existing template and write down every distinct presentation it produces, ignoring which section produced it. Most teams find five or six real presentations hiding behind fifteen named branches. That list is your type set, and it is derived from your own design rather than invented.
Find the accidental duplicates while you are there. This is where the near-identical chip rows and the two slightly different date formats surface. Deciding which wins should be deliberate, once, rather than inherited from whichever branch was written last.
Add the type-driven renderer as the fallback first. Instead of replacing the named branches, make the generic path type-aware. Immediately, every field nobody designed for stops looking broken, which is the largest share of the benefit and carries almost no risk to existing surfaces.
Then delete named branches one at a time, starting with the ones whose output the type renderer already matches. Each deletion is small, individually reviewable, and reversible. Some named branches will survive, and that is fine: a genuinely bespoke section is a legitimate thing to keep, as long as it is a deliberate exception rather than the default way of working.
The order matters because it front-loads the value. The fallback helps every unanticipated field on day one; the cleanup can go at whatever pace suits.
Two details that are easy to miss
Repeating groups need their own treatment. Anything a person can add several of, jobs, schools, certifications, projects, should render as a sequence of entry blocks rather than repeated label-value rows. Four jobs as four cards reads fine. Four jobs as twelve labelled lines is a wall. Make repeater a type in its own right and the problem disappears for content you have not thought of yet.
Display constraints on a value must survive the layout. If a date field is configured to show only the year, or only a derived age, every surface has to honour that: the detail page, the compact card, the API response. This is the one that leaks. A type-driven layout makes it easier to get right, because the constraint lives with the field rather than being reimplemented in each template, but only if you check every renderer rather than the main one.
The shortest way to state the rule: the person building a field already had to choose its type. Make that choice carry the layout, and there is nothing left to decide twice.
Where it does not apply
Being fair about the limits.
This pattern suits detail surfaces: profiles, product specs, entity pages, anything that is a set of attributes about one thing. It does not suit editorial layouts, where the whole value is that a human decided this pull quote goes here and that image spans full width. Do not try to derive an article layout from field types. You will build something that renders everything acceptably and nothing well.
It is also more upfront work for a fixed, small set of fields that genuinely will not grow. If you have six fields and you know it, render them by name and move on. The pattern earns its cost at the point where other people, or future you, start adding fields you did not anticipate.
That threshold arrives earlier than most teams expect. The moment your product lets a site owner define their own fields, you are past it, because at that point the set of fields is by definition not yours to know.
What it does to the rest of the design system
Two effects worth anticipating, because they change how the team works rather than just how the page looks.
Your token usage gets more disciplined by force. When the chip row is rendered once for every list in the product, its spacing, radius and colour cannot be one-off values. They have to come from tokens, because they are now describing a category of content rather than one section. Teams often find that adopting a type-driven layout does more for token adoption than a token adoption initiative did, simply because the alternative stops being available. Worth knowing which token system you are reaching for, though, since WordPress now has two of them and only one is theme.json. A type renderer that appears in both the front end and the admin has to answer that question explicitly.
Responsive and RTL work collapses from many problems into a few. A name-driven layout needs every section checked at every breakpoint and in both writing directions, and the list of sections grows forever. A type-driven layout needs the five or six value kinds checked properly, once. That is a fixed cost against an unbounded one, and it is the argument that usually persuades whoever owns the QA budget. It is also the point at which writing your CSS with logical properties rather than physical ones stops being a nicety and becomes the thing that keeps the fixed cost fixed, because a chip row built with margin-inline survives an RTL locale that a margin-left version does not.
The pattern does not remove design work. It moves it from the surface to the primitives, which is where it compounds.
The test
One question tells you which kind of layout you have.
Add a field group nobody designed for. A “Gaming setup” section, a “Coaching philosophy” group, whatever is furthest from what you had in mind. Give it a paragraph, a list and a link.
If it renders as considered as the sections that shipped, the layout is type-driven. If it comes out as a stack of generic label-value rows next to the nicely built ones, it is name-driven, and every field anyone adds from here will look like a guest in your design system.