Reactive stylesheets for SolidJS
solid-styled
Reactive stylesheets for SolidJS
Install
npm i solid-styled babel-plugin-solid-styled
yarn add solid-styled babel-plugin-solid-styled
pnpm add solid-styled babel-plugin-solid-styled
Features
- Render stylesheets only once
- Fine-grained reactive CSS properties
- Scoped stylesheets
:global
selector- SSR
Usage
Babel
Note: This is required for solid-styled
to work its magic properly!
{
"plugins": [
"babel-plugin-solid-styled"
]
}
<StyleRegistry>
<StyleRegistry>
manages the lifecycle of stylesheets. It is required only to be used once, preferably at the root of your SolidJS application
import { StyleRegistry } from 'solid-styled';
<StyleRegistry>
<App />
</StyleRegistry>
For SSR, you can pass an array to the styles
prop of <StyleRegistry>
. This array collects all of the "critical" (initial render) stylesheets, that which you can render as a string with renderSheets
.
import { renderSheets } from 'solid-styled';
const styles = [];
renderToString(() => (
<StyleRegistry styles={styles}>
<App />
</StyleRegistry>
));
// Render sheets
// You can use the resulting sheet by inserting
// it into an HTML template.
const styles = renderSheets(styles);
css
Use the css
tagged template for writing stylesheets.
import { css } from 'solid-styled';
function Title() {
css`
h1 {
color: red;
}
`;
return <h1>Hello World</h1>;
}
The template is also reactive. It works by replacing all templating values with a CSS variable. This allows the stylesheet to be only rendered once and can be shared by multiple components of the same scope.
import { css } from 'solid-styled';
function Button() {
const [color, setColor] = createSignal('red');
css`
button {
color: ${color()};
}
`;
return (
<button onClick={() => {
setColor((c) => (c === 'red' ? 'blue' : 'red'));
}}>
Current color: {color()}
</button>
);
}
By default, all styles are scoped to its component and cannot leak into another component. The scoping only applies all DOM nodes that can be found in the component, including the children of the external components.
import { css } from 'solid-styled';
function ForeignTitle() {
return <h1>This is not affected</h1>;
}
function Title() {
css`
h1 {
color: red;
}
`;
return (
<>
<h1>This is affected.</h1>
<ForeignTitle />
<Container>
<h1>This is also affected.</h1>
</Container>
</>
)
}
:global
Since all selectors in a given stylesheet are scoped by default, you can use the :global
pseudo selector to opt-out of scoping:
import { css } from 'solid-styled';
function Feed(props) {
css`
div > :global(* + *) {
margin-top: 0.5rem;
}
`;
return (
<div>
<For each={props.articles}>
{(item) => (
// This item is affected by the CSS of the Feed component.
<FeedArticle data={item} />
)}
</For>
</div>
);
}
@global
You can use @global
instead of :global
if you want to declare multiple global styles
css`
/* this is global */
@global {
body {
background-color: black;
}
main {
padding: 0.5rem;
}
}
h1 {
color: white;
}
`;
Forward scope
Since solid-styled
scopes valid elements and not components by default, it doesn't affect things like <Dynamic>
. Using use:solid-styled
, we can forward the current scope/sheet to the component.
css`
* {
color: red;
}
`;
<Dynamic component={props.as} use:solid-styled>
{props.children}
</Dynamic>
which compiles into
useSolidStyled('xxxx', '*[data-s-xxxx]{color:red}');
<Dynamic component={props.as} data-s-xxxx style={vars()}>
{props.children}
</Dynamic>
Limitations
- Scoping
css
can only be called directly on components. This is so that the Babel plugin can find and transform the JSX of the component. Globalcss
(i.e.:global
or@global
) can be used inside other functions i.e. hooks, utilities.
License
MIT © lxsmnsyc