v156 · css · houdini
Optional descriptors for registered custom properties
An @property rule used to demand all three descriptors: syntax, inherits, and — for any typed syntax — initial-value. Chrome 156 lets you omit any of them. What you leave out falls back to how an ordinary unregistered custom property already behaves, so a registration becomes a set of deliberate departures from the default rather than a form you have to fill in.
concepts
-
Descriptor lab
Toggle each descriptor on and off, watch the
@propertyrule rewrite itself, register it for real throughCSS.registerProperty(), and read back what the browser actually did — whether the rule was accepted, and what the computed value became. -
What each omission buys
Omitting a descriptor is not just less typing; each one changes behaviour. Three live test beds show what you gain and lose by dropping
syntax,inherits, andinitial-value— including the one people actually want, per-usevar()fallbacks on a typed property. -
Token sheet, before and after
A realistic design-token stylesheet written both ways, side by side, with the rules applied live to the same component. Counts the boilerplate the change removes and confirms the rendering is identical.
why it shipped
Registration exists to give a custom property a type, so it can animate, interpolate, and be rejected when it is set to nonsense. But the all-or-nothing form made authors repeat inherits: false hundreds of times across a token sheet, and — worse — forced an initial-value on every typed property. That last requirement is not merely verbose: an initial-value means var(--x, fallback) can never use its fallback, because the property always has a value. Authors who wanted per-use fallbacks had to give up typing entirely.
The CSSWG resolved that a registration should behave like an unregistered custom property except where the author says otherwise. Chrome 156 implements that, for both @property and CSS.registerProperty().
the API
/* Every descriptor was required. */
@property --brand-gap {
syntax: "<length>";
inherits: false;
initial-value: 0px;
}
/* Chrome 156: keep only what you mean to change. */
@property --brand-gap {
syntax: "<length>"; /* typed, so it can animate */
} /* inherits and initial-value left at their defaults */
/* And the same through CSSOM. */
CSS.registerProperty({ name: "--brand-gap", syntax: "<length>" });
Because the demos here measure the browser rather than trusting a version number, running them on Chrome 155 or earlier shows the old behaviour — an incomplete rule dropped on the floor — which is the clearest way to see what changed.