Fluent Flex · Chapter 05
Shape
Corner radius and stroke were scattered one-off values: irregular corners and vague comparative border names. Shape rebuilt them as two algorithmic scales where the value derives straight from the token name, with a nesting rule that keeps parents and children visually contained. The same values hold across web and mobile.
10 → 7
Corner radius tokens, now on a 4px algorithmic base
4
Stroke steps, renamed from comparative to an algorithmic scale
Why it matters
Small Decisions That Compound
Radius and stroke are small decisions that compound. Consistent corners and borders make a product feel deliberate and related rather than assembled from parts. Shape is the language for the form of an element: radius gives corners their character, and stroke draws the boundaries and emphasis where containment is needed.
Background
Scattered One-Off Values
Before Flex, both were case-by-case calls. Corner radius was an irregular ladder of hand-picked values that grew by inconsistent steps, with no formula connecting them and no rule for which component used which. Stroke widths were named by comparison, thin through thickest, with no stated reference point: thick compared to what? The names carried order, not logic, and the same weight showed up on borders, dividers, and focus rings with nothing to tell them apart.
Before
- Corner radius on an irregular progression, no formula between steps
- Comparative stroke names with no reference point
- No rule for which corner or border a component should use
- Hard for AI to infer the right value from context
After
- Corner radius: 10 tokens down to 7, on a 4px base
- Stroke: four steps on a 1px base, derived not compared
- The pixel value derives straight from the token name
- A nesting rule keeps a parent rounder than its child
The rebuild
One Model, Two Scales
The rebuild put both on the same model: an algorithmic scale where the pixel value derives
straight from the name. Radius runs on a 4px base and stroke on a 1px base, so a name like
radius-base-200 is simply two times the base. No lookup, no judgment call to add
a step.
Radius carries one thing stroke doesn't: a nesting rule. A parent's corners are always a step or more rounder than its child's, so nested corners stay concentric, the parent's curve wrapping cleanly around the child's rather than punching through it. Circular is a named exception for pills and avatars, and a surface flush to the screen edge simply squares off with 0px, because Flex doesn't tokenize zero: a token for nothing is a wasted one.
Stroke's four steps each have a job, from a default hairline for dividers and resting borders up to heavier weights for emphasis and large-surface treatments. It also powers selected states, and the system now has dedicated focus stroke tokens, so keyboard focus is defined once rather than reinvented per component.
Its rename was a systems call, too. Flex takes pride in never reusing a word across the system, and "thin" and "thick" had begun to collide with the material tokens. Moving stroke onto the same scalar scale as everything else kept every word doing exactly one job.
Radius is theme-scalable, and it is proven, not theoretical. Fluent 2 has always read tighter than Copilot, and there is a Fluent 2 theme built entirely from Flex tokens that renders the same components with those crisper corners while Copilot reads rounder. One component set, two radius characters, no redesign. It also retires a quiet cost of the old system: Fluent 2 kept extra radius tokens just to carry the rounder Copilot look, and a scale that theme-scales needs none of them. And adding a new value never means a wonky name wedged into the set, because scalar naming flexes where semantic names would break. That difference is exactly what the Copilot redesign put to the test. It all holds across web and mobile on one set of values; because mobile components are physically smaller, the same radius just reads a touch rounder there.
Collaboration
How This Came Together
Shape was mine to own, unifying corners and borders onto the same scalar model.
Looking ahead
What's Next
- Both scales feed AI-generated component specs: a model derives the right radius or stroke straight from the name, with no bespoke value per component.
- The nesting rule is encodable as a constraint, so tools can catch a child rounder than its parent before it ships.
- As the component library grows, the scales hold without manual additions; the math does the work.