Native
This guide assumes that you'll use opam (opens in a new tab) and dune (opens in a new tab) and have a server or native process running.
Install
opam install styled-ppx
Packages available
styled-ppx
is the ppx to transform[%styled.div ""]
and[%cx ""]
styled-ppx.native
is the library with the CSS bindings, and the implementation ofemotion.sh
on the server. Capable of storing CSS, hashing it and generating a unique classnames, autoprefixing, etc.
Usage
Add styled-ppx
under dune's preprocess pps for any library or executable. Add styled-ppx.native
as libraries.
(library
(name ...)
(libraries
+ styled-ppx.native
server-reason-react)
(preprocess
(pps
+ styled-ppx
melange.ppx
server-reason-react-ppx)))
(melange.emit
(target ...)
(libraries
+ styled-ppx.native
server-reason-react)
(preprocess
(pps
+ styled-ppx
melange.ppx
server-reason-react-ppx)))
Note: server-reason-react
and server-reason-react-ppx
are optional, and only needed if you use styled components ([%styled.div {||}]
).
API
CSS.get_stylesheet
returns a string with all stylesCSS.style_tag
returns a<style />
React element, with all styles. This is designed to be used with server-reason-react.
Example
let className = [%cx {|
display: flex;
width: 100%;
height: 100%;
justify-content: center;
align-items: center
|}];
let stylesheet: string = CSS.get_stylesheet();
print_endline(className);
/* .css-1xuw4bg */
print_endline(stylesheet);
/*
.css-1xuw4bg {
display: flex;
width: 100%;
height: 100%;
justify-content: center;
align-items: center;
} */
Example with server-reason-react
/* This is a server-reason-react module with those styles encoded as a unique className */
module Link = [%styled.a (~color=CSS.hex("4299E1")) => {|
font-size: 1.875rem;
line-height: 1.5;
text-decoration: none;
margin: 0px;
padding: 10px 0px;
color: $(color);
|}];
/* This is a unique className pointing to those styles */
let layout = [%cx {|
display: flex;
width: 100%;
height: 100%;
justify-content: center;
align-items: center
|}];
/* Later in a component */
let app =
<div className=layout>
<Link
color={CSS.hex("333333")}
href="https://sancho.dev"
rel="noopener noreferrer">
{React.string("sancho.dev")}
</Link>
</div>;
To generate the CSS on the server, you would need to use <CSS.style_tag />
. This component will render a <style>
with all generated stylesheet.
Given a Page
component to simulate a real-world scenario:
module Page = {
[@react.component]
let make = () => {
<html>
<head>
<CSS.style_tag />
</head>
</html>
}
}
If you're using dynamic CSS values, such as dynamic-components or interpolation based on runtime values. You would need to evaluate your app before extracting all the CSS.
module Component = {
[@react.component]
let make = (~value) => {
let className = switch (value) {
| Some(value) => [%cx "margin: $(value)"]
| None => [%cx "margin: 0"]
};
<div className />
}
};
This component needs to be rendered before the CSS.style_tag
otherwise the [%cx]
calls won't be added to the stylesheet, since they aren't being executed yet.
To solve this, we recommend: render the React application first, and then inject the result as dangerouslySetInnerHTML
.
/* `App` here is the entry component of your React application, while the `Document` component is only meant to run on the server. */
module Document = {
[@react.component]
let make = () => {
let app = ReactDOM.renderToString(<App />);
<html>
<head>
<CSS.style_tag />
</head>
<body>
<div id="#root" dangerouslySetInnerHTML={"__html": app} />
</body>
</html>
}
};
/* Let's asume we are running [dream](https://github.com/aantron/dream) */
let some_server_side_handler = _request => {
/* Here we render the entire HTML */
Dream.html(ReactDOM.renderToString(<Document />));
};
Advanced
If you don't want to render the stylesheet directly, you can use CSS.get_stylesheet
to obtain the stylesheet
as a string
. In this case, the hydration with the client won't be supported.
To make sure hydration works, you would need the following <style/>
tag
React.createElement "style"
[
Bool ("data-s", true);
String ("data-emotion", "css " ^ CSS.get_string_style_hashes ());
DangerouslyInnerHtml (CSS.get_stylesheet ());
]
[]