Easy syntax for stylesheet without Js.t
The problem
For new comers, having to use {"title": ...} & styles##title isn't straightforward.
Considered solution
We cannot use record in StyleSheet.create so we could write a simple ppx to help
[@react.stylesheet]
let styles = StyleSheet.create({title: ...})
// which will allow
styles.title;
I discussed with @bloodyowl about this & he told me a ppx solution should be easy to do.
Do you think that's a good idea to investigate?
(note: this will be optional & shouldn't be a breaking change in any sort)
Alternatives solutions
I don't see any.
@MoOx Does something similar to https://github.com/reasonml-labs/bs-css#usage-for-bs-css-dom have some compatible limit?
@tienle Nope. I just have to do with the way we define Js.t for "stylesheet" instead of record. Also we are using labeled arguments to ensure zero-cost bindings & bs-css is using function (like we were doing in bs-react-native)
@MoOx I see. Currently, I'm putting styles into a module like following:
module EmojiIcon = {
module Styles = {
open Style;
let container =
style(
~width=50.->dp,
~height=50.->dp,
~justifyContent=`center,
~alignItems=`center,
~margin=auto,
~backgroundColor="red",
~borderRadius=5.0,
(),
);
let text = textStyle(~fontSize=28.0, ~lineHeight=28.0, ());
};
[@react.component]
let make = (~emoji, ~style=?) => {
<View style=Styles.container>
<Text style=Styles.text> emoji->string </Text>
</View>;
};
};
Hence, Js.t thing is not bothering me much , and generated JS output is efficient as plain JS object since BS v.7 as well.
The label arguments with ~ characters all over around are not quite pleasant to read in comparison to the RN Javascript version. However, now I understand why it should be that way in term of zero-cost binding and type-safety :)
BTW, I'm starting to learn Reasonml and Reason RN, you are doing the great work. Thank you for keeping this up! ❤️ 💯
I wonder if we actually need StyleSheet.create. Its current implementation looks like this:
/**
* Creates a StyleSheet style reference from the given object.
*/
create<+S: ____Styles_Internal>(obj: S): $ReadOnly<S> {
// TODO: This should return S as the return type. But first,
// we need to codemod all the callsites that are typing this
// return value as a number (even though it was opaque).
if (__DEV__) {
for (const key in obj) {
StyleSheetValidation.validateStyle(key, obj);
if (obj[key]) {
Object.freeze(obj[key]);
}
}
}
return obj;
}
I.e. in dev mode, it validates the styles and freezes the style values. Apart from that, it just returns its input.
I think neither the validation nor the freezing make much sense when working in Reason.
So maybe we should just recommend @tienle's approach of putting the styles into a module.
Depending on the platform, implementation differ. For the web the implementation is much more complex as this split this into atom classes etc. Not sure we want to recommend approach depending on the targeted platform.
Also I think in the past this was different (returning {[key: string]: number} if I am correct) and this could change again ((or maybe not, I have no clue on the future of StyleSheet APIs)).
With new ReScript syntax, current state is imo worst than ever...

Does anyone have some skills so we could write a ppx that could transform this
@reactnative.styles
let styles = { key: style() }
as
type styles = { key: ReactNative.Style.t }
let styles = StyleSheet.create({ key: style() })
Is this a good idea in the first place?
@MoOx Is there any benefits of using StyleSheet.create rather than a module?
e.g.
module Styles = {
let style1 = style();
};
See 2 comments above https://github.com/reason-react-native/reason-react-native/issues/667#issuecomment-693267814
I've done some digging and am implementing a ppx rewriter for react-native-reanimated (especially the worklet syntax in Reanimated 2).
It seems that the most maintainable way would be to use Ppxlib, however, that also limits our PPX to use the extension interface
Similar to what is stated above, but more akin to:
%%stylesheet(let styles = { key: style() })
This will rewrite to
// numbered to allow multiple definitions within the same module
type reactnative_stylesheet__0 = { key: ReactNative.Style.t }
let styles: reactnative_stylesheet__0 = ReactNative.StyleSheet.create({ key: style() })
The other issue will be that this can only be used on "structure items", which means
%%stylesheet(let style1 = { key: style() }) // okay
module A = {
%%stylesheet(let style2 = { key: style() }) // okay
let make = (~something) => {
%%stylesheet(let style3 = { key: style() }) // doesn't work
something()
}
}
As somewhat of a side note, the Reason and OCaml syntax generated by this extension looks a lot nicer, essentially:
// Reason
let%stylesheet styles = { key: style() };
(* OCaml *)
let%stylesheet styles = { key = style () }
Since writing a PPX will mean integrating into the OCaml compiler framework, we'll need to:
- add esy as a dev dependency to enable any package consumer to be able to build the PPX themselves
- add a postinstall script to build and expose the PPX in the package
- instruct the package consumer to add to
bsconfig.json:
{
"ppx-flags": [..., ["rescript-react-native/ppx.exe", "-as-ppx"], ...]
}
See https://github.com/rescript-react-native/rescript-react-native/pull/739 for more info about what is next to do
#769 will make this kind of fixed.