How to Define CSS Custom Property Types with @property
The CSS @property rule, part of the CSS Houdini suite,
allows developers to register custom properties with explicit types,
inheritance behaviors, and default values. By providing strict type
definitions such as <color> or
<length>, browsers can properly validate values and
interpolate them during transitions and animations. This article
explains the syntax of the @property rule, how the
syntax descriptor enforces types, and how to implement
common types like colors and lengths in your stylesheets.
The @property Rule
Structure
Standard CSS custom properties (variables) are parsed as arbitrary
tokens, meaning the browser treats them as plain strings without
understanding what they represent. The @property at-rule
registers a custom property with a concrete data type using three
primary descriptors:
@property --my-property {
syntax: '<type>';
inherits: true | false;
initial-value: value;
}syntax: A string defining the permitted data types and structures.inherits: A boolean defining whether child elements inherit this property from parent elements.initial-value: The default fallback value for the property. This is required for almost all syntax definitions and must be valid according to the definedsyntax.
Defining <color>
Properties
To restrict a custom property to color values, set the
syntax descriptor to '<color>'. When a
property is registered as a <color>, the browser
parses inputs as actual color data. This enables smooth color
transitions and gradient animations that are otherwise impossible with
unregistered custom properties.
@property --theme-accent {
syntax: '<color>';
inherits: false;
initial-value: #3b82f6;
}
.box {
background: linear-gradient(var(--theme-accent), #000);
transition: --theme-accent 0.3s ease;
}
.box:hover {
--theme-accent: #ef4444;
}In this example, the browser interpolates --theme-accent
mathematically between the initial blue and the hover red across the
linear gradient.
Defining
<length> and <length-percentage>
Properties
The <length> type represents distance values,
accepting units such as px, em,
rem, vh, and vw. If a value
should accept either absolute lengths or relative percentages, you can
use the combined <length-percentage> type.
@property --card-padding {
syntax: '<length>';
inherits: true;
initial-value: 16px;
}
@property --element-width {
syntax: '<length-percentage>';
inherits: false;
initial-value: 100%;
}By defining --card-padding as a
<length>, invalid values (such as strings or unitless
numbers other than zero) are rejected, and the browser falls back to
16px.
Supported Data Types and Combinators
The syntax string supports standard CSS types and
combinations using specific operators:
- Common types:
<integer>,<number>,<percentage>,<angle>,<time>,<image>,<url>, and<transform-function>. - Alternatives (
|): Allows multiple acceptable types. For example,'<color> | auto'allows either a valid color or the literal keywordauto. - Space-separated lists (
+): Accepts one or more values separated by spaces. For example,'<length>+'allows values like10px 20px. - Comma-separated lists (
#): Accepts one or more values separated by commas. For example,'<color>#'allows a comma-separated sequence of colors. - Universal syntax (
'*'): Accepts any valid token stream, matching the behavior of standard untyped custom properties.
JavaScript
Equivalent: CSS.registerProperty
The exact same functionality can also be implemented through JavaScript using the CSS Houdini API:
window.CSS.registerProperty({
name: '--dynamic-size',
syntax: '<length>',
inherits: false,
initialValue: '0px',
});Using either CSS @property or
CSS.registerProperty ensures type safety, enables advanced
keyframe animations, and guarantees predictable fallbacks throughout
your stylesheets.