Configuration
To address a wide range of use cases, hooks are fully configurable. This flexibility means you can use our "recommended" hooks as a starting point and/or create your own custom set of hooks if you prefer.
Recommended hooks
Note
Requires TypeScript version 5.3 or later.
To get up and running with some sensible defaults, you can install
@css-hooks/recommended
via NPM or your package manager of choice, e.g.:
npm install @css-hooks/recommended
Then, in your src/css.ts
module (or equivalent), you can import and use the
recommended
function to conveniently configure a number of useful hooks:
import { createHooks } from "@css-hooks/react";
import { recommended } from "@css-hooks/recommended";
export const { styleSheet, css } = createHooks({
hooks: recommended({
// This creates media query hooks using the specified breakpoints:
// 1. @media (width < 500px)
// 2. @media (500px <= width < 1000px)
// 3. @media (1000px <= width)
breakpoints: ["500px", "1000px"],
// This creates media query hooks using the specified color schemes:
// 1. @media (prefers-color-scheme: dark)
// 2. @media (prefers-color-scheme: light)
colorSchemes: ["dark", "light"],
// This creates basic selector hooks for each of the pseudo-classes specified:
// 1. &:hover
// 2. &:focus
// 3. &:active
// 4. &:disabled
pseudoClasses: [":hover", ":focus", ":active", ":disabled"],
}),
});
To combine these with additional custom hooks, simply spread the returned object:
import { createHooks } from "@css-hooks/react";
import { recommended } from "@css-hooks/recommended";
export const { styleSheet, css } = createHooks({
hooks: {
...recommended({
// configuration for recommended hooks
}),
// custom hooks
},
});
Custom hooks
In cases where the recommended
function doesn't provide what you need, you can
fall back to defining custom hooks using the base hook configuration format.
That is, a record with each entry consisting of a hook name (the alias used to
reference the hook in conditional styles) and its implementation. For example:
import { createHooks } from "@css-hooks/react";
export const { styleSheet, css } = createHooks({
hooks: {
".group &:hover": ".group &:hover",
"&:intent": "&:hover, &:focus",
darkMode: ".dark &",
},
});
Hook syntax
Hooks are implemented using CSS syntax. Each hook may consist of a selector; a
@container
, @media
, or @supports
query; or a logical combination of any of
these.
Selectors
A hook that activates when the element matches a selector can be represented with a selector spec, e.g.
"&:hover"
: Activates when the cursor is positioned over the element.":checked + &"
: Activates when the previous sibling matches the:checked
pseudo-class.".group:hover &"
: Activates when an ancestor element has thegroup
class and matches the:hover
pseudo-class.".dark &"
: Activates when an ancestor has thedark
class.
The only change to native selector syntax is the use of &
as a placeholder for
the element where the hook is applied. For an overview of CSS selectors, see
CSS selectors (MDN).
Media queries
A media query hook activates when certain media types and/or features are matched, e.g.
"@media (prefers-color-scheme: dark)"
"@media (max-width:499px)"
"@media print"
For more information about media queries, see @media (MDN).
Container queries
A container query hook activates when the specified container condition(s) are matched, e.g.
"@container (width > 500px)"
"@container (width > 500px) or (height > 500px)"
"@container (width > 500px) and (height > 500px)"
To learn more, see @container (MDN).
Feature queries
A feature query hook activates when certain support conditions are matched, e.g.
"@supports (display: grid)"
"@supports (transform-origin: 5% 10%)"
"@supports font-format(woff2)"
See @supports (MDN) to learn more about feature queries.
Combinational logic hooks
CSS Hooks also provides helper functions that allow you to define complex hook logic by combining selectors and at-rules. You can think of each selector, at-rule, or combination as a condition.
- The
and
function accepts a variable number of condition arguments. It returns a condition that is true when all of the specified conditions are true. - The
or
function accepts a variable number of condition arguments. It returns a condition that is true when any of the specified conditions are true. - The
not
function accepts a single condition argument and returns the inverse condition.
To use these helper functions, modify the hooks
field of the configuration
object. Change the record to a callback function which returns the same record.
The helpers are then passed as a destructurable callback argument.
For example, imagine you want to implement a magic
@media (prefers-color-scheme: dark)
hook that takes a user setting into
account. Here's how that could be expressed using these helper functions:
export const { styleSheet, css } = createHooks({
hooks: ({ and, or }) => ({
"@media (prefers-color-scheme: dark)": or(
"[data-theme='dark'] &",
and("@media (prefers-color-scheme: dark)", "[data-theme='auto'] &"),
),
}),
});
Notice that the hook is activated when the user has explicitly configured a
theme setting ([data-theme="dark"]
attribute on an ancestor element) or when
the browser requests dark mode and the user has not configured a theme
([data-theme="auto"]
attribute on an ancestor element).
Options
Aside from hooks
, a few configuration options provide more granular control
over how CSS Hooks works.
debug
Default: false
When debug mode is enabled:
- The style sheet returned by the
styleSheet
function is pretty-printed. - Extra white space is included in inline style declarations for improved readability.
- Hook identifiers (underlying CSS variables) are tagged with user-defined hook names.
fallback
Default: "revert-layer"
The fallback
option specifies the CSS keyword to use when a conditional style
does not apply and a default value is not specified for one of the properties,
e.g.
<button
style={css({
on: $ => [
$("&:hover", {
color: "red",
}),
],
})}
>
...
</button>
In this case, the style object produced would look like the following:
{ "color": "var(--hover-on, red) var(--hover-off, <fallback>)" }
The configured value would be rendered in place of <fallback>
.
Functionally, the best choice is
"revert-layer"
,
which rolls back to a user-defined style sheet if present. On the other hand,
"unset"
rolls back
directly to the user agent style sheet, ignoring any user-defined style sheets;
but it has better compatibility with older browsers. For compatibility data,
please see
Web Platform Tests.
sort.properties
Default: true
When enabled, properties are sorted according to input order, with the last declaration having the highest priority.
When disabled, properties remain in the order in which they are first declared.
You may want to consider setting this to false
if you have implemented your
own algorithm for sorting properties.
Warning
This setting is experimental, and its non-default behavior may change subtly in
sort.conditionalStyles
Default: true
This setting affects the way declarations are prioritized when multiple rules
(style object arguments) are passed to the css
function.
When enabled, conditional styles are applied after all base styles, giving them higher priority.
When disabled, conditional styles defined in an earlier rule are overridden when the same property is declared in a later rule.
Disabling this option may be a good choice for libraries where each component
exposes a standard style
prop, accepting a flat style object and hiding CSS
Hooks as a private implementation detail. In this scenario, users would likely
expect client styles to override all previously-defined styles (even conditional
ones).
Warning
This setting is experimental, and its non-default behavior may change subtly in