Configuration
Register each selector, at-rule, and flag that your components will use by
passing it to createHooks(). The generated stylesheet evaluates these
conditions, while the component's style object supplies the declarations.
src/css.tsimport { createHooks } from "@css-hooks/react"; export const { on, and, or, not, enable, disable, styleSheet } = createHooks( "&:hover", "&:focus-visible", "&:active", "@media (hover: hover)", "@container (min-width: 320px)", "@supports (height: 100dvh)", "@scope ([data-theme='dark']) to ([data-theme])", "flag:dark", );
CSS selectors
Use & as a placeholder for the current element, i.e. the element whose style
object the hook filters. A selector must target that element, whether it
describes the element's own state or its surrounding context.
"&:hover" // The element is hovered. ".group:hover &" // The element is inside a hovered .group. ":checked + &" // The element follows a checked input.
At-rules
Hooks support @media, @container, @supports, @scope, and
@starting-style.
"@media (min-width: 600px)" "@container (min-width: 320px)" "@supports (height: 100dvh)" "@scope ([data-theme='dark']) to ([data-theme])" "@starting-style"
@scope hooks require an explicit scope root. They apply to the root and its
scoped descendants, excluding any scope limit and its descendants.
Flags
Register a flag:<name> hook to condition styles on inherited boolean state.
Registered flags are disabled by default. Use enable() or disable() with the
short flag name to set the state for an element's descendants:
const darkStyle = enable("dark"); const panelStyle = pipe( { background: "#fff", color: "#000" }, on("flag:dark", { background: "#000", color: "#fff" }), );
A nested setter overrides the inherited state for its subtree:
<main style={enable("dark")}> <section style={disable("dark")}>{/* Light subtree */}</section> </main>
The element carrying enable() or disable() still observes the state from its
nearest ancestor. Only its descendants observe the newly assigned state. This
also makes it possible to invert a flag without creating a custom-property
cycle:
const invertDark = pipe(enable("dark"), on("flag:dark", disable("dark")));
createHooks() only returns enable() and disable() when at least one flag
is registered. Their arguments are restricted to the short names of the flags
from that call.
Compose reusable conditions
Use and, or, and not to create conditions from other conditions/hooks.
export const hoverOnly = and("@media (hover: hover)", "&:hover"); export const intent = or(hoverOnly, "&:focus-visible");
For best results, create generic atomic hooks. A hook such as &:hover works on
its own and, through and, or, and not, combines with hooks such as
&:focus and &:enabled to express more specific conditions. The combinators
build on existing hooks, which promotes reuse and keeps the generated stylesheet
small.
Continue to Usage to apply these conditions with override styles.