Version 0.1.0 just released! Check out the release notes from GitHub Releases

Override a Third-Party Reset From a React Component by Lifting It Into a Higher CSS Cascade Layer

Priority Overrides in React

When a global reset or a third-party stylesheet wins against your component, the wrong answer is "add !important and move on." The right answer in Salty CSS is to lift the component into a higher CSS cascade layer with the priority option. Layers always win over each other regardless of selector specificity — and priority is just an integer (0–8) you set on the styled definition.

Set priority on the override

// /components/callout.css.ts
import { styled } from "@salty-css/react/styled";

// Lifts these rules into @layer l2, so they beat any l0/l1 rule
// at equal selector specificity — without changing the selector itself.
export const Callout = styled("div", {
  priority: 2,
  base: {
    background: "{colors.brand.main}",
    color: "white",
    padding: "1rem",
  },
});

The emitted CSS lands inside @layer l2 { ... }. Layers are declared in cascade order l0, l1, …, l8, so a higher number always wins.

That priority: 2 lands the rules in @layer l2. Salty CSS declares the layer order globally as imports, reset, global, templates, fonts, l0, l1, l2, … l8, so a rule in l2 beats anything in l0 or l1 even if both have the same selector specificity — and beats a global reset that lives in reset.

When a wrapper auto-bumps and when it doesn't

Salty CSS automatically raises the priority by one when you extend another component:

import { styled } from "@salty-css/react/styled";
import { Button } from "./button.css";

// Button is priority 0 (l0). PrimaryButton is auto-bumped to l1.
export const PrimaryButton = styled(Button, {
  base: { background: "{colors.brand.main}", color: "white" },
});

This is usually what you want — the wrapper sits above what it wraps. But it's a tie-breaker, not a fight-stopper:

// /components/button.css.ts
import { styled } from "@salty-css/react/styled";

// Lives in @layer l0 — `color: red` for any plain <Button />.
export const Button = styled("button", {
  base: { color: "red", padding: "0.5rem 1rem" },
});

// /components/primary-button.css.ts
import { styled } from "@salty-css/react/styled";
import { Button } from "./button.css";

// styled(Button, …) auto-bumps priority to 1, so this rule lives in
// @layer l1. Both rules have identical selector specificity, but
// l1 sits later in the cascade than l0 — `color: blue` wins.
export const PrimaryButton = styled(Button, {
  base: { color: "blue" },
});

Salty CSS does not rely on source order to decide ties — only layer order. Wrap a component to win; don't reach for !important or more specific selectors.

If you set priority: 0 explicitly on the wrapper, Salty CSS honours your intent and the auto-bump is suppressed.

Why not !important?

Inside CSS cascade layers, !important declarations follow an inverted layer order — declarations marked !important in the reset layer beat !important declarations in l0/l1/etc. That interacts badly with the layered priority system Salty CSS already gives you, and surprises everyone reading the rule a year later. Stick with priority for cross-layer overrides and reach for an inline style only when you genuinely want "wins everything, including the layer system."

What it produces

priority does not change the selector or add extra class chaining. The emitted CSS just lives inside @layer l2 { … } instead of @layer l0 { … }. The browser cost is zero; layer ordering is a static, declarative property of the stylesheet.

See also