Search code examples
cssreactjsreasonreason-react

What is the idiomatic way to create styles for a Reason-React component that depend on props?


To learn and , I'm working on a simple “Things 2 Do” app (see source code on GitHub).

I have a TodoItem component that should be rendered with strike-through style when the item has been completed.

I try to solve this by creating a record with various styles, similar to CSS classes, one root style and one for completed items.

type style = {
  root: ReactDOMRe.style,
  completed: ReactDOMRe.style
};

let styles = {
  root: ReactDOMRe.Style.make(), /* add root styles here */
  completed: ReactDOMRe.Style.make(~opacity="0.666", ~textDecoration="line-through", ())
};

If the prop completed is true, I combine the root style with the completed style, otherwise I just use the root, like this:

let style = styles.root;
let style = item.completed ? ReactDOMRe.Style.combine(style, styles.completed) : style;

This works, but it seems clunky, so I'm wondering: Is there a more elegant solution, e.g. using a variant and a switch statement?

What is the idiomatic way to create styles for a Reason-React component that depend on props?

Here is the full code of my component:

type item = {
  id: int,
  title: string,
  completed: bool
};

type style = {
  root: ReactDOMRe.style,
  completed: ReactDOMRe.style
};

let str = ReasonReact.stringToElement;

let component = ReasonReact.statelessComponent("TodoItem");

let styles = {
  root: ReactDOMRe.Style.make(), /* add root styles here */
  completed: ReactDOMRe.Style.make(~opacity="0.666", ~textDecoration="line-through", ())
};

let make = (~item: item, ~onToggle, _) => {
  ...component,
  render: (_) => {
    let style = styles.root;
    let style = item.completed ? ReactDOMRe.Style.combine(style, styles.completed) : style;
    <div style>
      <input
        _type="checkbox"
        onChange=((_) => onToggle())
        checked=(Js.Boolean.to_js_boolean(item.completed))
      />
      <label> (str(item.title)) </label>
    </div>
  }
};

Solution

  • I don't think there's anything that can be called idiomatic yet. The area is quickly changing, and even I have some ideas of my own on how to improve it, but this is more or less how I do it now using bs-css:

    module Styles = {
      open Css;
    
      let root = completed => style([
        color(white),
        opacity(completed ? 0.666 : 1.),
        textDecoration(completed ? LineThrough : None)
      ]);
    }
    
    ...
    
      render: _self =>
        <div className=Styles.root(item.completed)>
          ...
        </div>