Skip to content

VariableContextProvider treats "unset", "inherit" and "initial" differently from CSS #573

Open

Description

@jonthomp

Before submitting a new issue

  • I tested using the latest version of the library, as the bug might be already fixed.
  • I tested using a supported version of react native.
  • I checked for possible duplicate issues, with possible answers.

Bug summary

A CSS-wide keyword passed as a runtime variable value does not take its CSS meaning. Custom properties inherit, so unset and inherit take the parent's value, and initial is the guaranteed-invalid value, which makes a var() use its fallback (css-variables-1 §2, css-cascade-5 §7.3).

With an outer VariableContextProvider setting --my-var: red and an inner one setting the keyword, .test { color: var(--my-var, green) } renders:

Inner value main Browsers
"unset" no color red
"inherit" color: "inherit" red
"initial" color: "initial" green

"unset" clears because resolveValue turns the string "unset" into null for every value, which is how background-color: unset resets a style (#90). A variable holding "unset" goes through the same path, so the property that reads it is cleared. #431 kept that as the way to clear a variable from the runtime, and its test asserts it.

A possible fix, for VariableContextProvider and vars():

background-color: unset and the #431 behaviour for undefined stay as they are, and clearing stays available through "initial", which gives the result #431's "clears a variable with unset" test expects. The one change is that a runtime "unset" inherits, as in browsers, so that test would use "initial".

Does this match the intended semantics? If so, I'm happy to open a pull request. #503 covers the same keywords in compiled CSS (.child { --my-var: unset }), so the runtime side could reuse its representation of the guaranteed-invalid value.

Library version

3.1.0-rc.1 (main at 811f357)

Environment info

This repository's Jest suite on main, macOS, Node 24. Not platform specific.

Steps to reproduce

Add to src/__tests__/native/variables.test.tsx and run yarn test variables:

test.each([
  ["unset", "red"],
  ["inherit", "red"],
  ["initial", "green"],
])("VariableContextProvider %s", (keyword, expected) => {
  registerCSS(`
    .other { --my-var: blue; }
    .other-2 { --my-var: purple; }
    .test { color: var(--my-var, green); }
  `);

  render(
    <VariableContextProvider value={{ "--my-var": "red" }}>
      <VariableContextProvider value={{ "--my-var": keyword }}>
        <View testID={testID} className="test" />
      </VariableContextProvider>
    </VariableContextProvider>,
  );

  expect(screen.getByTestId(testID).props.style).toStrictEqual({
    color: expected,
  });
});

Reproducible example repository

Reproduces in this repository's own Jest suite (steps above).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions