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.

styled-ppx is a PPX and runtime library that brings styled components to ReScript, Melange, and OCaml. It lets you create React components — or plain className strings — backed by real CSS syntax, validated at compile time before your code ever runs. Instead of learning a new DSL, you write actual CSS inside extension nodes like %styled.div or %cx. The PPX runs before compilation, parses your CSS, type-checks it, and expands the extension into valid OCaml/ReScript code. If your CSS has a typo or an invalid value, you get a compile-time error — not a silent style bug at runtime.

A quick example

module Center = %styled.div(`
  height: 100vh;
  width: 100vw;
  display: flex;
  align-items: center;
  justify-content: center;
`)

<Center> {React.string("Hello from the future!")} </Center>
The Center module becomes a fully-typed React component whose className is generated at build time by hashing the CSS rules. No runtime CSS-in-JS parsing, no style objects, no API to memorise — just CSS.

Core extensions

styled-ppx exposes five extension points, each serving a distinct purpose:
ExtensionWhat it produces
%styled.div / [%styled.div]A React component wrapping a <div> (any HTML tag is supported)
%cx / [%cx]A className string from one or more CSS declarations
%css / [%css]A single Css.rule value, composable with the Array API
%keyframe / [%keyframe]A typed keyframe name for use in animation-name
%styled.global / [%styled.global]Injects global styles (resets, base typography, etc.)
The %ext syntax is used in ReScript. The [%ext] syntax is the equivalent for Reason and OCaml. Both forms are fully supported — the PPX transformation operates on the shared AST.

Dynamic styled components

Styled components accept labelled arguments that map directly to CSS interpolations, giving you type-safe dynamic styling without any runtime overhead:
module Link = %styled.a((~color=CSS.hex("4299E1")) => `
  font-size: 1.875rem;
  line-height: 1.5;
  text-decoration: none;
  color: $(color);
`)

<Link color={CSS.hex("333333")} href="https://example.com">
  {React.string("Click me")}
</Link>

Why styled-ppx instead of bs-css or bs-emotion?

Libraries like bs-css and bs-emotion are excellent, but they require you to learn a bespoke OCaml DSL that mirrors CSS — functions like backgroundColor, display \flex, px 16`, and so on. styled-ppx takes a different approach: write real CSS, get full type safety.
  • No new DSL to learn. If you know CSS, you already know how to use styled-ppx.
  • Smaller runtime. The PPX resolves and hashes styles at compile time; the runtime only needs to inject the pre-computed stylesheet into the DOM.
  • Better error messages. Parse errors and type errors are reported at the exact CSS source location, not as opaque OCaml type mismatches.
  • Works without React. %cx and %css can be used in any context — UI frameworks, server-side rendering, or plain native programs.

Platform support

styled-ppx integrates with three distinct platforms. Pick the guide that matches your project:

ReScript

Install via npm, configure bsconfig.json, and use %styled.div in your ReScript project within minutes.

Melange

Install via opam, add a dune stanza, and write Reason-syntax styled components for Melange React apps.

OCaml Native

Use styled-ppx.native for server-side rendering with server-reason-react and CSS.get_stylesheet().

Feature highlights

Zero abstraction over CSS

Write standard CSS syntax directly inside your source files. No wrapper functions, no style objects — the full CSS specification is available as-is.

Compile-time validation

The built-in CSS parser and type-checker reject invalid properties and values before your code compiles, eliminating an entire class of style bugs.

Component-based styling

%styled.div creates a real React component. It accepts all standard HTML props for its element, plus any labelled arguments you declare for dynamic styles.

Pattern-matching friendly

Because styles are plain OCaml values and className is a string, you can use pattern matching, composition, and labelled arguments just as you would with any other value.

Multi-platform

The same extensions work in ReScript (via npm), Melange (via opam + dune), and OCaml native (via opam + dune). The PPX targets the shared AST.

Server-side rendering

The styled-ppx.native runtime implements emotion’s hashing algorithm on the server. CSS.get_stylesheet() and CSS.style_tag let you collect and inject all styles for SSR.

Editor support

A VSCode extension and a vim plugin provide CSS syntax highlighting inside extension nodes.

Labelled class hashes

Generated classNames include the component or variable name (e.g. css-1xuw4bg-Link), making it easy to identify styles in browser DevTools.

How the PPX works

A PPX is OCaml’s macro system — a small program that runs before the compiler and transforms the source AST. styled-ppx intercepts every occurrence of %styled.*, %cx, %css, %keyframe, and %styled.global, parses the embedded CSS string, validates it against its own CSS type-checker, and replaces the extension node with the equivalent OCaml/ReScript code that calls into the runtime.
If you’re curious about the actual output, the snapshot tests in the repository show exactly what each extension expands to. You can also learn more about the OCaml PPX ecosystem in the Tarides blog post.

Build docs developers (and LLMs) love