How to get an indeterminate checkbox to work in ReScript?


I’ve been trying to build a read-only checkbox that would represent indeterminate state.
The read-only checkbox state would be derived from a list of items. If some items are not selected, then it should render the indeterminate state. Here is a basic example.

My lists are driven by hooks from rescript-recoil, so whenever I use this example component, it fails to render the indeterminate state in some specific cases, even when the prop is passed as Indeterminate.

The ref of the input tag is typed as ReactDOM.domRef - it rejects and function passed to it so I could go with %raw() but I dont want to.

What am I doing wrong with the ReadOnlyCheckbox component from the example which can cause React to ignore the input.indeterminate=true ?


If I understand correctly, the sequence of events in your component looks incorrect:

  1. Create the checkboxRef with initial value null
  2. Capture the current value null of the checkboxRef and convert it into an option in ref, so ref = None
  3. Pattern match on checkboxState and in each case call setIndeterminate if ref is Some value, which as per (2) is never
  4. Render the input

We need to swap some things around so the events are in the correct order:

  1. Create the checkboxRef with initial value null
  2. Render the checkbox with checked state based on the checkboxState
  3. Finally, call setIndeterminate to set the indeterminate state of the rendered checkbox:
module ReadOnlyCheckbox = {
  type checkboxState =
    | Unchecked //0
    | Indeterminate //1
    | Checked //2

  @set external setIndeterminate: (Dom.element, bool) => unit = "indeterminate"

  let make = (~checkboxState) => {
    let checkboxRef = React.useRef(Js.Nullable.null)

    React.useEffect(() => {
      checkboxRef.current->Js.Nullable.iter((. cb) =>
          switch checkboxState {
          | Unchecked | Checked => false
          | Indeterminate => true


      checked={switch checkboxState {
      | Unchecked | Indeterminate => false
      | Checked => true