Introducing form_props: The power of Rails forms now available for React!

Miss the convenience of Rails when working in React? Tired of building React forms ever so slightly different from project to project? Prefer working with HTML over customizing the Rails form builder? Prefer HATEOAS? Boy, do I have the tool for you!

Introducing form_props, a new member of the React ❤️ Rails family, which includes props_template, humid, and superglue. It’s a fork of Rails’s own form_with, made to output HTML attributes instead of HTML so you can wield the power of Rails’s form in React, and even React Native!

How it works:

Within a jbuilder or props_template file: new.json.jbuilder or new.json.props

json.create_form do
  form_props(@post) do |f|
    f.text :title
    f.submit
  end
end

Would output

{
  "createForm": {
    "props": {
      "id": "create-post", "action": "/posts/123", "accept-charset": "UTF-8", "method": "post"
    },
    "extras": {
      "method": { "name": "_method", "type": "hidden", "defaultValue": "patch", "autocomplete": "off"},
      "utf8": { "name": "utf8", "type": "hidden", "defaultValue": "\u0026#x2713;", "autocomplete": "off"}
      "csrf": {
        "name": "utf8",
        "type": "authenticity_token",
        "defaultValue": "SomeTOken!23$",
        "autocomplete": "off"
      }
    },
    "inputs": {
      "title": { "name": "post[title]", "id": "post_title", "type": "text", "defaultValue": "hello"},
      "submit": {"type": "submit", "defaultValue": "Create Post"}
    }
  }
}

then build a form component

import React from 'react'

export default ({props, inputs, extras}) => {
  <form {...props}>
    {Object.values(extras).map((hiddenProps) => (<input {...hiddenProps} type="hidden"/>))}

    // Bring your own components
    <input {...inputs.title} type="text"aria-label="Your Title"/>

    // or let the designer nest the input in the label. No form builder knowledge needed!
    <label for={inputs.title.id}>Your Title</label>

    <input {...inputs.submit} type="submit"/>
  </form>
}

and use the payload. If you’re using Superglue, this is passed to your page component:

export const newPostPage = (newPageProps)=> {
  const {header, createForm} = newPageProps;

  return (
    <>
      <h1>{header}</h1>
      <CreatePostForm {...createForm} />
    </>
  )
}

Otherwise, you’ll need to add it to your API, for example:

const [newPageProps, setNewPageProps] = useState(null);

useEffect(() => {
  const fetchData = async () => {
    const rsp = await fetch(`/api/posts/new`);
    setNewPageProps(rsp)
  };
});

Some helpers like f.select, and f.collection_checkboxes require you to build custom components.

Head over to the documentation for more information!