styled-ppx parses CSS string literals at compile time in one of three modes depending on which extension you use. Understanding the mode your extension operates in tells you what you can write inside the string and how the output will be scoped.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/davesnx/styled-ppx/llms.txt
Use this file to discover all available pages before exploring further.
Mode overview
| API | Mode | What it accepts |
|---|---|---|
%cx, %styled.tag | Declaration block | Declarations + nested selectors + nested at-rules |
%styled.global | Stylesheet | Top-level rules and at-rules as in a .css file |
%css | Single declaration | One property: value rule |
Declaration blocks
%cx and %styled.tag use the declaration-block grammar. You write the body of a rule, not the outer selector wrapper — styled-ppx generates the class selector and scopes nested rules to it automatically.
- Plain declarations
- Nested selectors (using
&or bare descendant selectors) - Nested at-rules:
@media,@supports,@container
Stylesheets
%styled.global parses a real stylesheet. Top-level selectors stay exactly as written and are not attached to any generated class.
Single declarations
%css accepts exactly one property: value pair — no selectors, no braces, no at-rules.
%css:
display: blockdisplay: block;(trailing semicolon is optional)
%css:
color: red; background: blue;— multiple declarations&:hover { color: red; }— selector block@media (...) { ... }— at-rule{ display: block }— outer braces
%cx or %styled.tag. See the %css reference for details.
Selectors and nesting
Declaration blocks support nested selectors.& stands for the current generated selector.
&) become descendants of the generated class:
- Type selectors:
div,button,svg path - Class, ID, and universal selectors:
.child,#main,* - Attribute selectors:
[disabled],[type="text"],[href^="https"] - Pseudo-classes:
:hover,:focus,:not(...),:is(...),:where(...),:has(...) - Pseudo-elements:
::before,::after,::first-line,::first-letter - Combinators: descendant,
>,+,~ - Comma-separated selector lists
At-rules
Declaration blocks support nested at-rules. Supported examples:%keyframe extension.
Interpolation
$(...) is supported in three positions:
- Declaration values — type-checked from the property’s expected type
- Selectors — string-like splice
- At-rule preludes — string-like splice
$(...). Arbitrary expressions are not supported — bind complex logic to a variable first and then interpolate the variable.
Edge cases
- The final semicolon of the last declaration is optional.
%cssrejects selectors, braces, and multiple declarations — use%cxfor those.- Declaration-block APIs (
%cx,%styled.tag) do not need an outer{ }wrapper; stylesheet APIs (%styled.global) do use outer selectors. - If a property is not yet supported, the recommended escape hatch is the Array API with
CSS.unsafe("-your-property", "value").