I’m brand new to Reason/ReScript and I’m evaluating how our team might use Reason in our React project.
We’ve hit one major stumbling block. Our project uses Theme UI for CSS-in-JS styling, which works like this:
- Each styled component gets a special
sx
prop that contains a style object. E.g.,<div sx={{ margin: '4px' }} />
. - Each
.jsx/.tsx
file that hassx
props in it is marked with a special JSX pragma at the top (e.g.,/** @jsx jsx */
), which tells Babel to usejsx(...)
calls instead ofReact.createElement(...)
. This behavior is part of Babel, not Theme UI, and you can use whatever function you like (in Babel’s docs, they usePreact.h
). Theme UI’sjsx
is a function likeReact.createElement
that also knows how to handle thesx
prop. It’s imported from Theme UI like so:import { jsx } from 'theme-ui'
.
So basically, I need to figure out how to use Theme UI’s jsx
function to create my elements rather than React’s createElement
. I also need to figure out how to get sx
into the prop type for JSX elements, but that’s another battle.
My first hunch was that the limitation had to do with ReasonReact, so I opened an issue.
I realized later that the limitation is at a deeper level, with something called the JSX ppx. It appears that ppx’s are an OCaml mechanism for extending the language through AST preprocessing?
I looked up that particular ppx. It appears that calls to React.createElement
are hardcoded, but it’s hard to tell if that’s a default or if it’s the only option.
Then, I came across this bit of documentation in the ReScript manual (under JSX->Tips and Tricks):
For library authors wanting to take advantage of the JSX: the
@JSX
attribute above is a hook for potential ppx macros to spot a function wanting to format as JSX. Once you spot the function, you can turn it into any other expression.This way, everyone gets to benefit the JSX syntax without needing to opt into a specific library using it, e.g. ReasonReact.
I’m not sure what “spot a function” means, but I naively tried writing @JSX div(~onClick=handler, ~children=list{child1, child2}, ())
and got this error: Unbound constructor JSX
.
I tried searching the ReasonReact source code for any mention of “jsx” and I couldn’t find any. I see the "reason": { "react-jsx": 3 }
in bsconfig.json, but I’m not sure how the ppx in ReScript and ReasonReact are connected, nor how I could leverage the ppx to support my own use case (i.e., Theme UI’s jsx
function).
Does anyone have an idea for how to tackle this problem? Thanks!