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.<tag> (ReScript) / [%styled.<tag>] (Reason) is the primary extension in styled-ppx. It transforms a CSS string written directly in your source file into a full React component whose styles are scoped automatically — no class-name collisions, no separate stylesheet, and full compile-time validation of every CSS property and value you write. Every HTML element has a matching extension point: %styled.div, %styled.button, %styled.input, %styled.span, %styled.section, %styled.a, and so on. The generated component passes all DOM props through to the underlying element while injecting the generated scoped className.

Basic example

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

<StyledComponent>
  {React.string("Hello from the style")}
</StyledComponent>
At compile time styled-ppx validates the CSS, generates a unique class name, and injects the styles into the page’s <head> via emotion. The module StyledComponent exposes a standard make function that accepts all the props of the underlying element.

React props (makeProps)

Every styled component automatically forwards all standard DOM props for its underlying element. If you style an input, you get placeholder, maxLength, onChange, onBlur, value, and everything else that ReactDOM.input accepts — no extra wiring needed.
module Input = %styled.input(`
  border: 1px solid #cccccc;
  border-radius: 4px;
  padding: 8px;

  &:focus {
    border-color: #aaaaaa;
  }
`)

<Input
  placeholder="Enter your name..."
  maxLength=255
  onChange={_ => ()}
  onBlur={_ => ()}
/>

Extending styles with className

Every styled component also accepts a className prop. When provided, the value is appended to the generated scoped class — useful when you need to bolt on utility classes or integrate with a third-party component library.
<Input
  placeholder="Enter your name..."
  maxLength=255
  onChange={_ => ()}
  onBlur={_ => ()}
  className="extra-classname"
/>
The resulting HTML places the generated emotion class first, followed by any class you pass:
<input class="css-fl09o-Input extra-classname" maxlength="255" placeholder="Enter your name...">
The className prop appends to the scoped class — it does not replace it. Styles defined in the external class follow the normal CSS cascade rules.

innerRef prop

Every styled component exposes an innerRef prop that forwards a React ref directly to the underlying DOM node. This is the standard way to call imperative DOM APIs (focus, scroll, measure) on a styled element.
module Input = %styled.input(`
  border: 1px solid #cccccc;
  border-radius: 4px;
  padding: 8px;
  font-size: 16px;
  outline: none;

  &:focus {
    border-color: #aaaaaa;
  }
`)

@react.component
let make = () => {
  let input = React.useRef(Js.Nullable.null)

  let focusInput = () =>
    input.current
    ->Js.Nullable.toOption
    ->Belt.Option.forEach(input => focus(input))

  let onClick = _ => focusInput()

  <div>
    <Input innerRef={ReactDOM.Ref.domRef(input)} />
    <button onClick> {React.string("Click to focus")} </button>
  </div>
}
See React Ref for the full reference on forwarding refs with styled-ppx.

Dynamic components

%styled.<tag> can also be written as a function that receives labelled arguments and returns a CSS string. The types of those arguments are inferred directly from the CSS properties they appear in — no type annotations required.
module Dynamic = %styled.div((~color, ~background) => `
  color: $(color);
  background-color: $(background);
`)
See Dynamic Components for a full walkthrough including type inference, name-collision warnings, and default prop values.

Array API

Both %styled.<tag> and %cx can accept an array of Css.rule values instead of a CSS string. This unlocks conditional styles, variable references, function calls, and pattern matching inside your component definitions.
module Button = %styled.button([
  buttonStyles,
  boolean ? %css("width: 100%;") : %css("width: auto"),
])
See Array API for composability patterns and the full feature set.

Build docs developers (and LLMs) love