Recent chats
ASKGEEZ Q&A GUIDETechnology & devices

How do custom properties inherit, and when does @property change that behavior?

Quick answer

An unregistered --name custom property inherits from its parent unless another declaration overrides it. Registering a property with @property lets you specify whether it inherits, what value types it accepts, and its initial value. Use registration when those rules are useful; otherwise, ordinary inheritance is often enough. Registration does not guarantee identical browser support everywhere.

LET’S WORK THROUGH IT

The question, the details, the next step.

Question

If I set --accent on a parent, what happens on its children? Is it like a variable the browser stores globally?

Geez

An unregistered custom property such as --accent inherits from its parent, so a descendant can use the value unless it has its own applicable declaration. It is not a global variable: the value follows the element tree and can differ between branches. Its value is resolved where it is used, rather than being stored and reused across unrelated elements. [S1]

For example:

:root {
  --accent: teal;
}

.card {
  color: var(--accent);
}

.card.special {
  --accent: rebeccapurple;
}

A regular .card gets the inherited teal value from :root. A .card.special uses its own rebeccapurple declaration; descendants of that special card inherit that value unless they override it. A separate branch of the document tree is not changed just because one card overrides the property.

Follow-up question

What does registering it with @property change? Could you show the same kind of setup?

Geez

Registration lets you set rules for the property instead of relying on the usual inheritance behavior. In particular, syntax describes accepted value types, inherits controls inheritance, and initial-value provides a starting value. A registration needs both syntax and inherits. [S2]

Here is a separate example for a length-valued spacing property:

@property --panel-gap {
  syntax: "<length>";
  inherits: false;
  initial-value: 0px;
}

.panel {
  --panel-gap: 1rem;
}

.panel .item {
  margin-block-start: var(--panel-gap);
}

With inherits: false, .item does not inherit the 1rem value declared on .panel. In this example, it uses the registered initial value, 0px, unless it has its own --panel-gap declaration. The syntax descriptor identifies the intended value type; it does not make this property inherit.

Follow-up question

How do I choose between inheriting and not inheriting, and what should I watch for in the registration?

Geez

Choose inheritance based on how you want the value to travel through the element tree. A theme-like value that descendants should share may suit inherits: true; a value intended to apply only where it is set may suit inherits: false. These are design choices, not guarantees about what a particular page should use.

Check the registration details carefully. For non-universal syntax, initial-value is required and must be computationally independent. It may be omitted only when the syntax is universal (*). [S2] For instance, the <length> registration above uses 0px as its initial value. Registration guidance does not establish identical support in every browser, so check the browsers relevant to your project before relying on it.

Follow-up question

Can you give me a quick way to test whether I set it up as intended?

Geez

Make a small page with a parent, two children, and one child that overrides the property. First test an unregistered property: set a value on the parent, use it on both children, then override it on just one child. Next, register a separate property with an explicit syntax, inheritance setting, and initial value; compare the child that has no declaration with the child that does.

Write down the expected value for each element before checking the rendered result. That separates three questions: what the parent declares, whether the child inherits, and what initial value applies. If behavior differs across your target browsers, investigate support for registration before making it a requirement. These examples illustrate inheritance rules; they do not establish browser-by-browser support.

A practical checklist

  • Identify the element where the custom property is declared and trace its descendants.

  • Check whether an unregistered property is overridden on the element or an ancestor branch.

  • For @property, specify both syntax and inherits.

  • Provide an appropriate initial-value for non-universal syntax; make it computationally independent.

  • Test a child with no declaration and one with an override in relevant browsers.

A few more useful answers

Does `inherits: false` mean the property has no value on a child?

No. It means the registered property does not inherit from its parent. The registered initial value can apply when the child has no value of its own.

Can I omit `initial-value` from every registration?

No. It may be omitted only with universal syntax (*). Otherwise, it is required and must be computationally independent. [S2]

Does `@property` guarantee the same behavior in every browser?

No such guarantee is established here. Check support in the browsers relevant to your project before depending on registration.

Sources

References used for this guide.

  1. [S1] Using CSS custom properties — MDN
    developer.mozilla.org · Checked
  2. [S2] Registering custom properties in CSS — MDN
    developer.mozilla.org · Checked

YOUR QUESTION. YOUR DETAILS.

Let’s work through your situation.

Get a tailored answer or help with your next task. Starts at $1, with a quote before you pay.

Ask your own question
← Back to Geez at Work