Three widths, and no more.

A stroke is one of three weights. Each aliases a primitive directly, the way spacing does, so a border never carries a raw number, not even a 1px one. They do not fork by brand or density. A hairline is a hairline in both houses and at both densities.

  • td.border.width.smBorder width sm - the default hairline. 1px.1px
  • td.border.width.mdBorder width md - emphasis, selected and hover states. 1.5px.1.5px
  • td.border.width.lgBorder width lg - the heaviest stroke, for strong emphasis. 2px.2px

Picking one

Reach for sm unless you have a reason not to. It is the default hairline, and it carries dividers, input and card outlines, and table rules. Most interfaces need nothing else.

Step up to md when a stroke has to read as deliberate, whether that is a selected card, a hovered input, anything where the border is carrying state rather than structure. Keep lg for strong emphasis, and use it rarely enough that it still means something.

Width is not the whole border

These tokens set thickness only. The color comes from the border roles on the color page, which is why a stroke can change weight and hue independently. Focus indicators are a separate matter again. Thread uses the browser’s own, so there is no focus width token to reach for.