Skip to main content

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.

%cx and %styled.* support CSS selectors and nested rules. The %css extension does not — it only generates a single Css.rule value. The nesting syntax is similar to SASS: you must use & in front of any selector that should be combined with the generated class name.

Basic nesting

Use & to attach pseudo-classes, pseudo-elements, or modifier classes directly to the generated selector:
let link = %cx(`
  color: $(Color.Text.body);

  &:hover {
    color: $(Color.Text.accent);
  }
`)
Nested selectors are automatically attached to the generated class name. In the example above, &:hover expands to .generated:hover, where .generated is the class produced by %cx.

Nesting depth caveat

More than one level of nesting may compile without errors but will produce incorrect CSS output. Keep selector nesting to a single level.

Supported selector features

The parser accepts CSS Selectors Level 3 and the stable parts of the Level 4 draft:
  • Type selectorsdiv, button, svg path
  • Class, ID, and universal selectors.child, #main, *
  • Attribute selectors[disabled], [type="text"], [href^="https"]
  • Pseudo-classes:hover, :focus, :target, :not(...), :is(...), :where(...), :has(...)
  • Pseudo-elements::before, ::after, ::first-line, ::first-letter
  • Combinators — descendant ( ), child (>), adjacent sibling (+), general sibling (~)
  • Comma-separated selector lists

Interpolation in selectors

You can interpolate OCaml/ReScript identifiers inside selector strings. This is especially useful for composing class names generated by other %cx calls.
// `outlined` is a class name generated by %cx, but any string works
let outlined = %cx(`
  padding: 4px;
  outline: 1px solid red;
`)

let link = %cx(`
  color: $(Color.Text.body);

  & .$(outlined) {
    padding: 0px;
  }
`)

<div className={link ++ " " ++ (isActive ? outlined : "")} />
Inside selectors, $(...) behaves like string splicing — the identifier’s runtime string value is inserted directly into the selector. This makes it possible to reference a generated class name from one component as a descendant selector in another.
Interpolation in selectors works the same way as interpolation in media query preludes. In both cases the value is treated as a raw string fragment rather than a typed CSS value. See Media Queries for the analogous pattern with breakpoints.

Build docs developers (and LLMs) love