Composition and Precedence
How Pigment CSS handles css precedence and composition.
Styles authored with Pigment CSS will be scoped to the component and won’t affect globals styles or styles of any other styled components. This is mainly done by using uniquely generated class names that are hard to override through global styles since you don’t know the class names beforehand.
In a way, it is similar to CSS Modules except, the styles are written in JS and colocated with the components.
Precedence
The order of writing the styles determine which styles take precedence (similar to CSS) and not which class name is the last one being applied.
import { css } from '@pigment-css/react-new';
const bgRed = css`
color: red;
`;
const bgBlue = css`
color: blue;
`;
// Case 1
function App() {
return (
<div className={`${bgRed} ${bgBlue}`}>
<p>Hello, world!</p>
</div>
);
}
// or Case 2
function App() {
return (
<div className={`${bgBlue} ${bgRed}`}>
<p>Hello, world!</p>
</div>
);
}
In the above example, the color of the text will be blue
in both the cases because the final generated css will have the styles in the same order -
.bg-red {
color: red;
}
.bg-blue {
color: blue;
}
The above example can be extended to imported styles or styled components as well.
import { css } from '@pigment-css/react-new';
export const Button = styled.button`
padding: 8px 16px;
border: none;
border-radius: 4px;
background-color: #0070f3;
color: white;
font-size: 14px;
cursor: pointer;
transition: background-color 0.2s;
&:hover {
background-color: #0051cc;
}
&:active {
background-color: #003da6;
}
&:disabled {
background-color: #ccc;
cursor: not-allowed;
}
`;
import { css } from '@pigment-css/react-new';
import { Button } from './Button';
const bgBlue = css`
color: blue;
`;
function App() {
return <Button className={`${bgBlue}`}>Click me</Button>;
}
In the above example, the color of the text will be blue
because the styles are generated in the reverse order of the imports.
.button {
color: #fff;
cursor: pointer;
background-color: #0070f3;
border: none;
border-radius: 4px;
padding: 8px 16px;
font-size: 14px;
transition: background-color 0.2s;
}
.button:hover {
background-color: #0051cc;
}
.button:active {
background-color: #003da6;
}
.button:disabled {
cursor: not-allowed;
background-color: #ccc;
}
.bg-blue {
color: blue;
}
Layers
All the generated styles, either through css
, keyframes
or styled
calls, are all added to a layer named pigment.base
.
So any css authored outside of Pigment CSS (css or css-modules or Tailwind) will have a higher precedence than the Pigment CSS styles.
So if you are applying reset styles through global css, you may need to wrap some of those styles in a layer named pigment.globals
. Here are all the Pigment CSS layers in the order of precedence -
pigment.globals
— User defined global styles.pigment.utils
— All the theme tokens are added to this layer.pigment.base
— Base styles.pigment.variants
— Variant styles (refer to the variants section for more details).pigment.compoundvariants
— Compound variant styles (refer to the variants section for more details).
Composition
You can compose values of css()
or styled()
calls to override the base styles.
With styled calls
import { styled } from '@pigment-css/react-new';
export const Link = styled.a`
display: flex;
align-items: center;
padding: 5px 10px;
color: pink;
`;
Here, the color of text in the Link
component will be pink
.
import { styled } from '@pigment-css/react-new';
import { Link } from './Link';
export const Heading = styled.h1`
font-weight: 600;
font-size: 24px;
${Link} {
color: black;
}
`;
import { Heading } from './Heading';
function App() {
return (
<Heading>
This is a <Link>heading</Link>
</Heading>
);
}
Here, the color of text in the Link
component will be black
because the Link
component’s color is overridden by the Heading
component’s styles.
.link {
display: flex;
align-items: center;
padding: 5px 10px;
color: pink;
}
.heading {
font-weight: 600;
font-size: 24px;
}
.heading .link {
color: black;
}
Existing styled components created using Pigment CSS can be composed via the styled
function by passing the component as a parameter to the styled
function.
import { styled } from '@pigment-css/react-new';
const Button = styled.button`
padding: 8px 16px;
border: none;
border-radius: 4px;
background-color: #0070f3;
color: white;
font-size: 14px;
cursor: pointer;
transition: background-color 0.2s;
&:hover {
background-color: #0051cc;
}
&:active {
background-color: #003da6;
}
&:disabled {
background-color: #ccc;
cursor: not-allowed;
}
`;
const HeroButton = styled(Button)`
background-color: #ff4081;
font-size: 16px;
padding: 12px 24px;
&:hover {
background-color: #ff4081;
}
&:active {
background-color: #ff4081;
}
`;
With css calls
import { css } from '@pigment-css/react-new';
export const linkCls = css`
display: flex;
align-items: center;
padding: 5px 10px;
color: pink;
`;
Here, the text color of the element where linkCls
will be applied will be pink
.
import { styled } from '@pigment-css/react-new';
import { linkCls } from './link';
export const Heading = styled.h1`
font-weight: 600;
font-size: 24px;
.${linkCls} {
color: black;
}
`;
import { Heading } from './Heading';
function App() {
return (
<Heading>
This is a <span className={`${linkCls}`}>heading</span>
</Heading>
);
}
Here, the text color of the element where linkCls
will be applied will be black
because the Heading
component’s style override the color of the linkCls
styles.
note You’ll have to add the class selector to the
linkCls
, ie,.linkCls
instead of justLink
in thestyled
usage.