This is the latest docs version
Quick Links
  • -Overview
  • -Language Features
  • -JS Interop
  • -Build System
Documentation
Language Manual
Reference for all language features
ReScript & React
First class bindings for ReactJS
GenType
Seamless TypeScript integration
Reanalyze
Dead Code & Termination analysis
Exploration
Packages
Explore third party libraries and bindings
Syntax Lookup
Discover all syntax constructs
APIPlaygroundBlogCommunity
  • Playground
  • Blog
  • Twitter
  • GitHub
  • Forum
rescript-react
Overview
  • Introduction
  • Installation
  • Migrate from JSX v3
Main Concepts
  • Elements & JSX
  • Rendering Elements
  • Components and Props
  • Arrays and Keys
  • Refs and the DOM
  • Context
  • Styling
    • Inline Styles
    • Global CSS
    • CSS Modules
    • CSS Utility Libraries
    • CSS-in-JS
  • Router
  • Lazy Components
Hooks & State Management
  • Hooks & State Management Overview
  • useEffect Hook
  • useState Hook
  • useReducer Hook
  • useContext Hook
  • useRef Hook
  • Build A Custom Hook
Guides
  • Beyond JSX
  • Forwarding Refs
  • Extensions of props
Docs / rescript-react / Styling
Edit

You are currently looking at the v0.12.0 docs, which are still a work in progress. If you miss anything, you may find it in the older v0.11.0 docs here.

Styling

React comes with builtin support for inline styles, but there are also a number of third party libraries for styling React components. You might be comfortable with a specific setup, like:

  • Global CSS / CSS modules

  • CSS utility libraries (tailwindcss, tachyons, bootstrap etc.)

  • CSS-in-JS (styled-components, emotion, etc.)

If they work in JS then they almost certainly work in ReScript. In the next few sections, we've shared some ideas for working with popular libraries. If you're interested in working with one you don't see here, search the package index or post in the forum.

Inline Styles

This is the most basic form of styling, coming straight from the 90s. You can apply a style attribute to any DOM element with our ReactDOM.Style.make API:

RES
<div style={ReactDOM.Style.make(~color="#444444", ~fontSize="68px", ())} />

It's a labeled (therefore typed) function call that maps to the familiar style object {color: '#444444', fontSize: '68px'}. For every CSS attribute in the CSS specfication, there is a camelCased label in our make function.

Note that make returns an opaque ReactDOM.Style.t type that you can't read into. We also expose a ReactDOM.Style.combine that takes in two styles and combine them.

Escape Hatch: unsafeAddProp

The above Style.make API will safely type check every style field! However, we might have missed some more esoteric fields. If that's the case, the type system will tell you that the field you're trying to add doesn't exist. To remediate this, we're exposing a ReactDOM.Style.unsafeAddProp to dangerously add a field to a style:

RES
let style = ReactDOM.Style.make( ~color="red", ~padding="10px", (), )->ReactDOM.Style.unsafeAddProp("-webkit-animation-name", "moveit")

Global CSS

Use a %%raw expression to import CSS files within your ReScript / React component code:

RESCRIPT
// in a JS module setup %%raw("import './styles/main.css'") // or with CommonJS %%raw("require('./styles/main.css')")

CSS Modules

CSS modules can be imported like any other JS module. The imported value is a JS object, with attributes equivalent to each classname defined in the CSS file.

As an example, let's say we have a CSS module like this:

CSS
/* styles.module.css */ .root { color: red }

We now need to create a module binding that imports our styles as a JS object:

RES
// {..} means we are handling a JS object with an unknown // set of attributes @module external styles: {..} = "./styles.module.css" // Use the obj["key"] syntax to access any classname within our object let app = <div className={styles["root"]} />

Note: {..} is an open JS object type, which means the type checker will not type check correct classname usage. If you want to enforce compiler errors, replace {..} with a concrete JS object type, such as {"root": string}.

CSS Utility Libraries

Tailwind

CSS utility libraries like TailwindCSS usually require some globally imported CSS.

First, create your TailwindCSS main entrypoint file:

CSS
/* main.css */ @tailwind base; @tailwind components; @tailwind utilities;

Then, import your main.css file in your ReScript / React application:

RES
// src/App.res %%raw("import './main.css'")

Utilize ReScript's pattern matching and string interpolations to combine different classnames:

RES
@react.component let make = (~active: bool) => { let activeClass = if active { "text-green-600" } else { "text-red-600" } <div className={`border-1 border-black ${activeClass}`}> {React.string("Hello World")} </div> }

Hint: rescript-lang.org actually uses TailwindCSS under the hood! Check out our codebase to get some more inspiration on usage patterns.

CSS-in-JS

There's no way we could recommend a definitive CSS-in-JS workflow, since there are many different approaches on how to bind to CSS-in-JS libraries (going from simple to very advanced).

For demonstration purposes, let's create some simple bindings to e.g. emotion (as described here):

RES
// src/Emotion.res @module("@emotion/css") external css: {..} => string = "css" @module("@emotion/css") external rawCss: string => string = "css" @module("@emotion/css") external keyframes: {..} => string = "css" @module("@emotion/css") external cx: array<string> => string = "cx" @module("@emotion/css") external injectGlobal: string => unit = "injectGlobal"

This will give you straight-forward access to emotion's apis. Here's how you'd use them in your app code:

RES
let container = Emotion.css({ "color": "#fff", "backgroundColor": "red" }) let app = <div className={container} />

You can also use submodules to organize your styles more easily:

RES
module Styles = { open Emotion let container = css({ "color": "#fff", "backgroundColor": "red" }) // your other declarations } let app = <div className={Styles.container} />

Please note that this approach will not check for invalid css attribute names. If you e.g. want to make sure that only valid CSS attributes are being passed, you could define your css function like this as well:

RES
@module("@emotion/css") external css: ReactDOM.Style.t => string = "css" // Usage is slightly different (and probably less ergonomic) let container = ReactDOM.Style.make(~padding="20px", ())->css; let app = <div className={container} />

Here we used the already existing React.Style.t type to enforce valid CSS attribute names. Last but not least, you can also bind to functions that let you use raw CSS directly:

RES
let container = Emotion.rawCss(` color: #fff; background-color: red; `) let app = <div className={container} />

Please keep in mind that there's a spectrum on how type-safe an API can be (while being more / less complex to handle), so choose a solution that fits to your team's needs.

ContextRouter

© 2024 The ReScript Project

Software and assets distribution powered by KeyCDN.

About
  • Community
  • ReScript Association
Find us on