Files
webstudio/docs/university/foundations/css-variables.md
T
Oleg Isonen 1b48716ff4 docs: Document MDX-backed Content Blocks (#6273)
## Summary

- Document how people create, connect, edit, validate, and publish
MDX-backed Content Blocks.
- Document the complete MCP workflow, including scoped expression
sources, frontmatter updates, diagnostics, conflicts, and disconnect
behavior.
- Add two focused screenshots for the human workflow.
- Fix issues found by a low-reasoning MCP agent while executing every
documented workflow.

Ref #6182

## Implementation notes

- Connection confirmation uses the public `confirmReplacement` field
because `confirm` is reserved as a hidden transport field.
- MCP edits frontmatter with `update-content-block-frontmatter`;
materialized MDX elements are not persistent targets for generic
instance mutation tools.
- Reload now intentionally discards a conflicted local source and
accepts the Asset's latest storage revision before an edit is reapplied.
- Generated MCP documentation and runtime contracts are updated from
their source files.

## Checklist

- [x] Document the human MDX Content Block workflow.
- [x] Document MCP discovery, connection, editing, diagnostics,
frontmatter, dynamic sources, conflicts, and disconnection.
- [x] Add only screenshots that clarify otherwise hard-to-describe UI
steps.
- [x] Test every documented MDX capability through the local MCP CLI
with a low-reasoning agent.
- [x] Reproduce and fix the replacement-confirmation schema mismatch.
- [x] Reproduce and fix persistent-session conflict reload and reapply.
- [x] Add regression tests that failed before each product fix and pass
afterward.
- [x] Regenerate runtime contracts and generated MCP documentation.
- [x] Review authoritative `docs/` content and update affected pages.
- [x] Run affected tests, typechecks, formatting, and diff checks.

## Verification

- Project Build: 208 affected tests passed.
- Content Engine Asset session: 8 tests passed.
- CLI documentation tests: 14 tests passed.
- MCP docs generator: 3 tests passed.
- Content Engine, Project Build, CLI, and MCP docs typechecks passed.
- `pnpm oxfmt --check` passed.
- `git diff --check` passed.
- Low-reasoning MCP evaluation passed all documented workflows,
including a real two-client revision conflict, reload, reapply, and
final saved inspection.
2026-08-31 18:39:05 +02:00

11 KiB
Raw Blame History

description
description
CSS variables allow you to attach a value to a variable and reuse that variable throughout the Style Panel inputs.

🧱 CSS variables

{% hint style="info" %} Hint: Data variables are different than CSS variables. They enable the reuse of data in the Settings tab. {% endhint %} {% embed url="https://www.youtube.com/watch?v=NrU_9BZytQY" %}

Why Use CSS variables?

  • Consistency – Define a value once, like a color, and access that variable in every style input field.
  • Speed – Design quickly by selecting predefined variables from autocomplete.
  • Experimentation – Arrow through autocomplete and get real-time rendering of that variable to see which value looks best in your design.
  • Parent-child interactions – Have full control over the styles of all child instances when interacting with the parent.

CSS variables vs. Tokens

The concept of “reusability” is present in both CSS variables and Tokens, but they are different and complement each other exceptionally well.

Let’s think of these two concepts as layers or building blocks.

Layer 1: CSS variables

CSS variables are the bottom layer. They comprise individual variable names and values often used for sizes, colors, and other styles with many input options. Craft distinguishes theme variables, which contain theme-specific inputs, from semantic variables, which describe how a value is used.

For colors, define a small set of theme variables and derive semantic variables from them. For example, --theme-accent can control --background-accent, --border-focus, and their interaction states. Tokens consume the semantic variables, so changing a theme input updates the complete system without editing each color independently.

Layer 2: Tokens

Tokens are the next layer. They package up multiple styles. Craft calls these composite Tokens. A Card Token may include padding, color, and gap styles, for example.

The values you enter for each style should be defined as variables. This approach ensures consistent designs and allows you to update a value in one place, with the change automatically reflected wherever the variable is used.

With CSS variables, Tokens now often take a more semantic approach, such as calling them Card, Team Member, or Testimonial. Without CSS variables, Tokens were a blend between semantic and utility, such as padding-medium, font-size-small, and Card.

{% hint style="info" %} Tip: While some utility Tokens will still be present, the majority of Tokens should be semantic. {% endhint %}

Creating variables

{% hint style="warning" %} Before you create custom variables, review Craft, Webstudio's public specification for theme variables, semantic variables, composite Tokens, and reusable project architecture. {% endhint %}

A CSS variable is defined in the Advanced section by using two dashes followed by the variable name, like this:

--gray-5

{% hint style="info" %} This syntax is not unique to Webstudio. It’s the official CSS variable syntax. {% endhint %}

Then, the variable's value can be anything such as a color, gradient, duration, size, or number.

CSS variable

Creating a variable and assigning a value

Using variables

Once the variable is defined, you can use it on the instance it was defined on and any of its children.

The variables are available in the autocomplete, so you can access variables by typing them in.

Using a CSS variable

The autocomplete search algorithm is very flexible, letting you search by any of the following:

  • --
  • var
  • gray (variable name)

You can search any part of your variable, and autocomplete will show you the proper results.

{% hint style="info" %} The syntax for displaying a variable isvar(--my-var), though it's much faster to search using --. Webstudio automatically handles the conversion to ensure proper output. {% endhint %}

Using data to set CSS variables

The common pattern is to generate a <style> tag via an HTML Embed expression, populate that tag with CSS variable definitions, and then consume those variables in the Advanced section or any style field. You can learn more about writing the bindings themselves in the Expression editor documentation.

The general pattern looks like this:

  1. Create the data variable with CSS variables you intend to use (you can do that on HTML Embed instance or any parent). You can use a JSON type or Resource type depending on where your data is coming from.

    Define CSS variables
    Step 1: define your variables in the Settings panel.
  2. Add an HTML Embed component somewhere on the page, ideally at the top (head section is a good place but body works too) and create a binding on the code property.

    Insert HTML Embed
    Step 2: drop an HTML Embed onto the canvas and bind the code property.
  3. Write a template literal in Expression editor that produces a <style> block. Within the style block, interpolate whatever data you want. A couple of common patterns are shown below:

    // key‑value style
    `<style>
      :root {
        --brand-color: ${dataVariables.themeColor};
        --feature-width: ${dataVariables.featureWidth}px;
      }
    </style>`;
    
    // entire CSS string from a JSON field
    `<style>
      :root {
         ${dataVariables.variables}
      }
    </style>`;
    

    The ${} expressions can reference any value accessible in the Expression editor, including nested properties and ternary logic. The second form is useful when an API returns a single string containing multiple declarations.

    Note: you don’t need any special escaping; dataVariables.variables uses the standard JavaScript syntax to refer to a nested field. Since the HTML Embed evaluates whenever its dependencies change, the resulting <style> tag will update with new values. The variables it defines are now available everywhere on the page.

    {% hint style="warning" %} Variables created via an HTML Embed are not picked up by the style‑panel autocomplete. You must type the variable name manually (or copy/paste it) when referencing it later. {% endhint %}

  4. In Advanced section or any style inputs, refer to the variables with var(--brand-color).

    Use CSS variable in style input
    Step 5: reference the variable in any style value input.

This technique is powerful for theming, A/B testing, or applying dynamic values such as colors or dimensions fetched from an API and managed by an external CMS.

Scope

CSS variables, by nature, are available in the current instance and any of the children.

Global Variables

Navigator with Global root above Body and the page instance tree

Most variables should be defined on the Global Root, which is the highest level of the page and the same for every page. That way, you can define --my-color, and it's available on every instance on every page.

Local variables

Some variables are only needed on a specific section or page. You can define these variables on a common ancestor of where they need to be accessed, such as a Box/wrapper.

Here are some use cases for local variables:

  • Changing a child's design when interacting with the parent (see Parent-child interactions for more info).
  • Doing an A/B test without modifying the entire design system
  • Running a seasonal promotion and modifying colors for a section

Parent-child interactions

With CSS variables, you can interact with the parent and modify the styles of any of the children.

Prefer CSS variables over a descendant custom state such as :hover .button for parent-child interactions. They keep each property on the child that uses it and are especially useful when one parent state coordinates several properties or children. Define a variable on the parent, use it for the relevant property on each child, and change the variable's value in the parent's :hover state.

Hovering a link changes its child icon color, background, and arrow visibility

Hovering the link and the children change (icon color, icon bg, and arrow appears)

{% embed url="https://youtu.be/rg49mmDvdlE" %} Video tutorial {% endembed %}

Here are the high-level steps to accomplish this pattern:

  1. Take note of the various properties you want to change such as color and background color.
  2. Create a variable on the parent for each style property such as --child-color and --child-bg. Leave the values empty for now.
  3. Add the variables to the various children's style inputs, such as setting background to --child-bg (no style changes will happen yet because the variables don't have values).
  4. Go back to the parent, where the variables are defined, and give them values for the default state.
  5. Switch to the other state, such as hover, and change the variables' values.
  6. Interact with the parent and see the child change!

{% hint style="info" %} For step 2, it's possible to define variables and assign values all at once, but it's better to add the variables to the children first. If the variables aren't added to the children, the assigned values won't render anywhere, which makes it difficult to determine things like which color to use. {% endhint %}

Example Variable Names

For a navigation hover effect:

  • --nav-icon-bg – Icon background color
  • --nav-icon-color – Icon fill color
  • --nav-arrow-opacity – Arrow visibility
  • --nav-arrow-translate – Arrow position

Adding Transitions

Add transitions on the child instances (not the parent) to smooth out the changes:

  • On the icon: add transitions for background-color and color (~200ms duration)
  • On the arrow: add transitions for opacity and translate (~200ms duration)

You can define as many variables as you want and use them on any children where they are defined to create more complex interactions.