borders lab

The edge of a glass surface is three stacked layers: the generated specular rim (follows the light), the CSS hairline (uniform) and the pointer glow (rides the hairline). Each row below moves exactly one of them. Hover the tiles — the glow band thins with the hairline.

component gallery · optics probe

Specular rim width — specularWidth, intensity at the 0.35 default

The generated rim, from hairline-thin to well past the clamp. The library now derives 1.5px for this bezel — the iOS reference value — where it used to derive 2.2px.

1px
1.5px — default
2.2px — previous
3px
4px

Specular intensity — specularIntensity, width left at the default

Same rim, dimmer. This one is a live filter attribute, so unlike the width it can be animated — a control could rest light and brighten on hover.

0.2
0.35 — default
0.55
0.8 — previous

CSS hairline — --lg-border-width, specular at its defaults

The uniform liseré under the specular. The pointer glow band is 1.25× this value, so at 0 the hover glow disappears with it — the two are meant to read as one edge.

0px
0.5px — default
1px — previous
1.5px

Candidates at control scale

Border weight is judged on a 44px pill, not a card. The specular survives in all four — only its weight moves. The second pill is what the library now ships; the first is what it shipped before the iOS 26 comparison. Flip the scheme and the backdrop before judging.

previous

previous defaults — 2.2px @ 0.8, 1px hairline

default

shipped defaults — 1.5px @ 0.35, 0.5px hairline

fine

fine — 1px @ 0.6, 0.5px

whisper

whisper — 1px @ 0.25, 0.5px

iOS 26 reference — dark circular button

The screenshot is the target. What it says about the edge: the rim is ~1px, very dim (reads nearer 0.3 — the shipped default is 0.35), carried by the top-left / bottom-right diagonal, and the uniform hairline under it is barely there. All three glass circles share the reference's dark material — the tint colour is overridden to iOS's dark grey — so the edge is the only thing that differs. The rim's double arc now sits on that same diagonal: SPECULAR_LIGHT_ANGLE is the CSS layers' 145° light restated, after living at 60° and quietly fighting every gradient under it. The residual difference is that our two arcs are equally bright (|N·L|) where iOS's lower one is a touch fainter.

iOS 26 circular button on a black background
iOS 26 screenshot
previous

previous defaults — 2.2px @ 0.8, 1px hairline

default

shipped defaults — 1.5px @ 0.35, 0.5px hairline

faint

1px @ 0.25, 0.5px hairline

iOS light — the same recipes on a light stage

Same three edges, same geometry, but the material flipped to iOS light mode: the default white tint over the system grey background. This is the harder case for the rim — a white highlight over a near-white material barely registers, which is why iOS leans on the drop shadow and the hairline here and lets the specular whisper. If a recipe holds up on both this stage and the black one, it holds up.

previous

previous defaults — 2.2px @ 0.8, 1px hairline

default

shipped defaults — 1.5px @ 0.35, 0.5px hairline

faint

1px @ 0.25, 0.5px hairline

Playground

edge
playground

specularWidth=1.5 specularIntensity=0.35 style="--lg-border-width: 0.50px"

The width slider regenerates the specular map on each step — fine here, but it is part of the map cache key, so in a component it is a value to set, not to animate. Intensity and the hairline are live.