Skip to content

Commit 22cd611

Browse files
committed
Add styling section to rescript-react docs
1 parent 7db0600 commit 22cd611

File tree

2 files changed

+171
-0
lines changed

2 files changed

+171
-0
lines changed

data/sidebar_react_latest.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"arrays-and-keys",
1212
"refs-and-the-dom",
1313
"context",
14+
"styling",
1415
"router"
1516
],
1617
"Hooks & State Management": [

pages/docs/react/latest/styling.mdx

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
---
2+
title: Styling
3+
description: "Styling in ReScript & React"
4+
canonical: "/docs/react/latest/styling"
5+
---
6+
7+
# Styling
8+
9+
There are many different approaches on how to do styling in React, such as:
10+
11+
- Inline Styles (`style=...`)
12+
- Global CSS / CSS modules
13+
- CSS utility libraries (`tailwindcss`, `tachyons`, etc.)
14+
- CSS-in-JS (such as `styled-components`, `emotion`, etc.)
15+
16+
## Inline Styles
17+
18+
You can apply a `style` attribute to any DOM element with our `ReactDOM.Style.make` API:
19+
20+
```rescript
21+
<div style=(
22+
ReactDOM.Style.make(~color="#444444", ~fontSize="68px", ())
23+
)/>
24+
```
25+
26+
It's a labeled (typed!) function call that maps to the familiar style object `{color: '#444444', fontSize: '68px'}`.
27+
28+
**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 `style`s and combine them.
29+
30+
### Escape Hatch: `unsafeAddProp`
31+
32+
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:
33+
34+
```reason
35+
let myStyle = ReactDOM.Style.make(~color="#444444", ~fontSize="68px", ());
36+
37+
## Global CSS
38+
39+
Use a `%%raw()` expression to import CSS files within your ReScript / React component code:
40+
41+
```rescript
42+
%%raw("require('./styles/main.css')")
43+
44+
// or with ES6
45+
%%raw("import './styles/main.css'")
46+
```
47+
48+
## CSS Modules
49+
50+
CSS modules can be imported like any other JS module. The imported value is a JS object, with each key mapping to a classname within the imported CSS file.
51+
52+
As an example, let's say we have a CSS module like this:
53+
54+
```css
55+
/* styles.module.css */
56+
57+
.root {
58+
color: red
59+
}
60+
```
61+
62+
We now need to create a module binding that imports our styles:
63+
64+
```res
65+
// {..} means we are handling a JS object with an unknown
66+
// set of attributes
67+
@module external styles: {..} = "./styles.module.css"
68+
69+
let app = <div className={styles["root"]} />
70+
```
71+
72+
**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}`.
73+
74+
75+
## CSS Utility Libraries
76+
77+
### Tailwind
78+
79+
80+
CSS utility libraries like [TailwindCSS](https://tailwindcss.com) usually require some globally imported CSS.
81+
82+
First, create your TailwindCSS main entrypoint file:
83+
84+
```css
85+
/* main.css */
86+
87+
@tailwind base;
88+
@tailwind components;
89+
@tailwind utilities;
90+
```
91+
92+
Then, import your `main.css` file in your ReScript / React application:
93+
94+
```res
95+
// src/App.res
96+
97+
%%raw("import './main.css'")
98+
```
99+
100+
Utilize ReScript's pattern matching and string interpolations to combine different classnames:
101+
102+
```res
103+
@react.component
104+
let make = (~active: bool) => {
105+
let activeClass = if active {
106+
"text-green-600"
107+
}
108+
else {
109+
"text-red-600"
110+
}
111+
112+
<div className={`border-1 border-black ${activeClass}`}>
113+
{React.string("Hello World")}
114+
</div>
115+
}
116+
```
117+
118+
When using the [Tailwind VSCode plugin](https://tailwindcss.com/docs/intellisense), make sure to include ReScript as a target language to get autocompletion:
119+
120+
- Open the VSCode settings
121+
- Search for `Tailwind CSS: Include Languages`
122+
- Add a new item with following settings:
123+
- Item: `rescript`
124+
- Value: `html`
125+
126+
127+
> **Hint:** `rescript-lang.org` actually uses TailwindCSS under the hood! Check out our [codebase](https://github.com/rescript-association/rescript-lang.org) to get some more inspiration on usage patterns.
128+
129+
130+
## CSS-in-JS
131+
132+
Currently there are no official recommendations for CSS-in-JS yet due to the wildly different approaches on how to bind to CSS-in-JS (going from simple to very advanced).
133+
134+
The most minimalistic approach is to create simple bindings to e.g. [`emotion`](https://emotion.sh/docs/introduction) (as described [here](https://github.com/bloodyowl/rescript-react-starter-kit/blob/eca7055c59ba578b2d1994fc928d8f541a423e74/src/shared/Emotion.res)):
135+
136+
```res
137+
// src/Emotion.res
138+
139+
@module("@emotion/css") external css: {..} => string = "css"
140+
@module("@emotion/css") external keyframes: {..} => string = "css"
141+
@module("@emotion/css") external cx: array<string> => string = "cx"
142+
143+
@module("@emotion/css") external injectGlobal: string => unit = "injectGlobal"
144+
```
145+
146+
This will give you straight-forward access to the `emotion` apis. Here's how you'd use them in your app code:
147+
148+
```res
149+
let app = <div
150+
className={Emotion.css({
151+
"color": "#fff",
152+
"backgroundColor": "red"
153+
})}
154+
/>
155+
```
156+
157+
Please note that this approach will not be type-checking for valid 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:
158+
159+
```res
160+
@module("@emotion/css") external css: React.Style.t => string = "css"
161+
162+
// Usage is slightly different (and probably less ergonomic)
163+
let app = <div
164+
className={ReactDOM.Style.make(~padding="20px", ())->css}
165+
/>
166+
```
167+
168+
In the example above we used the already existing `React.Style.t` type to enforce valid CSS attribute names. There's a spectrum on how type-safe an API might be, so choose a solution that fits your team's needs.
169+
170+
For more CSS-in-JS ideas, you can also check out related discussions on our [forum](https://forum.rescript-lang.org), or start a new topic.

0 commit comments

Comments
 (0)