The typographic internals of button text — units, line-height, letter-spacing — and the width rules that govern how buttons grow, shrink, and hold their shape.
Every button font-size, padding, and border-radius is expressed in a unit. The choice between px, rem, and em isn't cosmetic — it determines whether a button scales with user preferences, with its own font-size, or with nothing at all.
| Unit | Relative to | Strengths | Risks |
|---|---|---|---|
| px | Nothing (absolute) | Pixel-perfect. Predictable everywhere. No inheritance surprises. Best for borders, shadows, and visual details that shouldn't scale. | Ignores user font-size preferences. Fails WCAG if used for body text font-size. Requires manual adjustment at every breakpoint. |
| rem | Root element (:root / html) | Scales with user's browser font-size setting. Consistent across the page — 1rem means the same thing everywhere. The accessibility standard for font-size. | Doesn't create component-internal proportionality. A 0.5rem padding doesn't know what font-size it's next to. |
| em | The element's own font-size | Creates self-scaling components. If padding is in em, changing the font-size scales the entire button proportionally. The most elegant approach for button size variants. | Can compound unpredictably in nested elements (though this doesn't affect buttons, which are leaf nodes). Requires mental math: 0.625em of what? |
Font-size in rem. This is the accessibility baseline. Setting button font-size in rem means that when a user increases their browser's default font size (for low vision, for preference, for comfort), button text scales with it. Using px for font-size overrides this preference — it's one of the most common accessibility failures on the web, and one of the easiest to avoid.
Padding in em. This is what makes button size variants elegant. If padding is expressed in em (relative to the button's own font-size), then changing the font-size automatically scales the padding. A single font-size change creates a proportionally larger or smaller button without touching any other property. This is the technique advocated by Ahmad Shadeed, Donnie D'Amato, and implemented in several modern token systems.
Border-radius in em or px. If radius is in em, it scales with the button — a larger font-size produces proportionally rounder corners. If radius is in px, it stays fixed regardless of button size, which can look oddly small on XL buttons or oddly large on XS buttons. The em approach is more internally consistent; the px approach gives you more explicit control.
Border-width in px. A 1.5px border should be 1.5px whether the button is small or large. Border-width is a visual detail, not a proportional dimension. Scaling it with font-size produces borders that look too thick on large buttons and disappear on small ones.
Line-height in buttons behaves differently than in paragraphs. In body text, line-height creates spacing between lines. In buttons, there is (almost always) a single line of text — so line-height determines the internal vertical rhythm of the text block within the button, and it can affect the button's overall height if you're not careful.
line-height: 1 (or 1em) makes the text block exactly the height of the font's cap-height plus descenders. This produces the tightest vertical centering and the most predictable button height. It's the most common choice in design systems because it gives padding full control over vertical space.
line-height: 1.2–1.25 adds a small buffer around the text. This can improve the vertical centering of certain fonts that have unusual ascender/descender ratios. It's a pragmatic middle ground.
line-height: 1.5 (the body text default) is usually too tall for buttons. It adds visible extra space above and below the text that makes padding values feel larger than intended. If your button inherits line-height from body text, the button will be taller than you designed it.
Letter-spacing (tracking) is the space between individual characters. In button text, it's primarily a tool for readability at small sizes and for controlling the visual density of uppercase labels.
Normal (0) is the safe default for sentence-case button labels at 13–16px. The font's built-in spacing is almost always correct at these sizes.
Slight tightening (-0.01 to -0.02em) is used by some modern systems (Linear, Vercel) at medium and large button sizes. It gives the text a slightly more compact, "designed" feel. This only works with fonts that have generous default tracking — tightening a font that's already tight produces illegible results.
Wide tracking (0.04–0.12em) is required for uppercase labels. All-caps text at normal tracking looks cramped because uppercase letters have more uniform widths and less natural rhythm than mixed-case. The USWDS specifically recommends adding letter-spacing to uppercase button text. The wider the tracking, the more "editorial" or "architectural" the button feels.
Letter-spacing should always be specified in em, not px. This ensures the tracking scales proportionally with font-size — 0.08em of tracking on a 12px label is ~1px, which is appropriate; 0.08em on an 18px label is ~1.5px, which is also appropriate. Fixed-px tracking breaks at different sizes.
One of the most common CSS gotchas: <button> elements do not inherit font-family from their parent by default. Browsers apply their own default font (typically a system sans-serif that may not match your design system's typeface). The fix is trivial but easy to forget:
This reset should be in your global stylesheet. Without it, your button text will render in the browser's default font, not your design system's chosen typeface — a subtle but pervasive inconsistency that's easy to miss in development and obvious in production.
By default, a button is as wide as its text plus its horizontal padding. This is almost always the right behavior. But there are four common situations where you need to override it — and each one has a different CSS solution.
The natural state of a button is display: inline-flex (or inline-block), with width determined by its content. This is correct for the vast majority of buttons in application UIs. The text label dictates the width; padding provides breathing room; the button is only as large as it needs to be.
Content-driven width breaks down when the label is very short. A button labeled "OK" or "Go" with standard padding becomes a tiny, hard-to-click rectangle. The solution is min-width.
A min-width of 80–120px (or 5–7.5em) prevents buttons from becoming uncomfortably small while still allowing them to grow naturally with longer labels. This is the approach used by Carbon, SAP Fiori, and most enterprise design systems. Always combine min-width with horizontal padding — if only min-width is set and padding is removed, a long label could touch the button edges.
A full-width button spans the entire width of its container. This is the standard treatment in three contexts: mobile forms (where the button becomes a full-width touch target at the bottom of the screen), modal footers (where the confirmation action spans the modal width), and stacked card actions (where each button fills the card width).
The CSS is simple: width: 100% or display: flex on the parent with flex: 1 on the button. The design decisions are about context: full-width buttons work when there is one primary action and the container is narrow enough that the button doesn't look like a banner. On a 1200px desktop layout, a full-width button looks absurd. Use max-width to cap it:
The clamp() function is the modern alternative: width: clamp(200px, 100%, 400px) creates a button that is full-width in narrow containers, capped at 400px in wide ones, and never narrower than 200px.
When two or more buttons sit side-by-side — "Cancel" and "Save," for example — their different label lengths create different widths. This is visually uneven and can feel unbalanced, especially in dialog footers.
Two approaches to equalize:
Flexbox with flex: 1. Both buttons share equal space. The shorter label gets more padding; the longer label gets less. This is simple and works well for 2–3 buttons, but can produce uncomfortably wide buttons if one label is much shorter than the others.
CSS Grid with 1fr columns. Similar result, but grid gives you more control over minimum column widths and is better suited for groups of 3+ buttons.
In practice, the best approach depends on whether visual symmetry or natural proportion is more important to your design language. Some systems (Apple, shadcn/ui) prefer natural width with sufficient min-width. Others (Carbon, SAP) prefer equal-width groups for the cleaner alignment.
What happens when the label is too long for the available space? This arises in three scenarios: the label was written too long (a content problem), the label was translated into a longer language (a localization problem), or the container is too narrow at a responsive breakpoint (a layout problem). There are three CSS responses:
Wrapping (white-space: normal) lets the text flow to a second line. This preserves all the text but creates a taller button, which can break vertical rhythm and look inconsistent next to single-line buttons. It's the safest option for accessibility — no text is hidden — but it's the most visually disruptive. Use it as a last resort, and set a tighter line-height (1.2–1.3) to keep the wrapped button from becoming too tall.
Truncation (text-overflow: ellipsis) clips the text and adds "…" to signal that more text exists. This preserves the button's height and shape but hides potentially critical information. If you truncate, you should ideally provide a tooltip on hover that shows the full label. Truncation is best for situations where the button label is supplementary (like a file name in a "Download report-q3-2024-final-v2.xlsx" button), not where the label is the primary instruction.
Clipping (overflow: hidden without ellipsis) is the worst option — it hides text without any visual cue that text was hidden. Avoid this.
When configuring width behavior for your button primitive, the decisions cascade:
1. Default to content-driven width. width: auto with horizontal padding. This handles 80% of button use cases.
2. Set a min-width. Prevent buttons from becoming too small with short labels. 80–120px (or 5–7.5em) is the standard range. Always keep horizontal padding present alongside min-width.
3. Offer a full-width variant. width: 100% for mobile forms, modals, and stacked layouts. Cap with max-width for desktop contexts where the container is wider than ~400px.
4. Set white-space: nowrap as the default. Button labels should not wrap. If they do, the label is too long. Handle overflow with truncation + tooltip rather than wrapping, unless wrapping is explicitly designed for.
5. In flexbox containers, add min-width: 0. This prevents flex items from overflowing their container when the label is long — a known flexbox behavior that D'Amato and Kevin Powell have documented extensively. Without it, a long label can push the button beyond its flex container.
This isn't a CSS question, but it governs every width decision. The best button labels are 1–3 words. Some guidelines from current practice:
| Words | Examples | Guidance |
|---|---|---|
| 1 | Save, Send, Cancel, Delete, Share, Submit | Ideal for primary actions. Universally understood. No width issues. The gold standard. |
| 2 | Get started, Sign up, Learn more, Add item, Export CSV | The most common label length. Clear, scannable, fits comfortably in most layouts. |
| 3 | Save and close, Create new project, Go to dashboard | Acceptable. Start watching for width issues in tight layouts and at small button sizes. |
| 4+ | Save changes and continue, Download full report as PDF | Too long. Refactor the label or move the explanation into surrounding copy. Four-word buttons often indicate that the button is trying to explain itself — the UI around it should be doing that work. |
For internationalization, plan for 30–50% text expansion in translation. A label that fits perfectly in English may overflow in German, Finnish, or Greek. This is where min-width (preventing tiny buttons in short-word languages like Chinese) and truncation strategies (handling expansion in long-word languages) both become essential. The em-based padding system from Section A1 helps here — because the padding scales with font-size, and localized text is usually set at the same font-size, the proportions hold even as the label length changes.
Part IV of the Button Taxonomy. Parts I–III cover structure, contrast, construction, and hover behavior.
The best button text is the shortest text that's still clear.