---
title: 'Introducing form_props: The power of Rails forms now available for React!'
teaser: We've built form_props, a powerful Rails form helper to use with React.
tags: ruby,web,ruby on rails,json,superglue,jbuilder
author: Johny Ho
published_on: 2024-04-10
---

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`

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

Would output

```json
{
  "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

```js
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!

[documentation]: https://github.com/thoughtbot/form_props
[form_props]: https://github.com/thoughtbot/form_props
[superglue]: https://thoughtbot.com/blog/introducing-superglue
[props_template]: https://github.com/thoughtbot/props_template
[humid]: https://github.com/thoughtbot/humid
