React Netlify Forms

Full Stack Developed by: Donald Boulton Follow Don on Twitter🙌 0
|
Aug 12, 20217 min readReact, Netlify  Category Tech

React Netlify Forms

React components and hooks giving you the power of Netlify Forms. Start building serverless forms on Netlify with React. Honeypot fields and reCAPTCHA are included as ready-to-use components.

Go to documentation with live demo.

Features

It gives you all the features of Netlify Forms as simple and reusable React components which have been tested on Netlify.

  • Default form handlers with support for file uploads.
  • Spam prevention through included honeypot and reCAPTCHA components.
  • Can be used alone or together with form libraries such as Formik or react-hook-form.

Before using

This component must be used with Server-Side Rendering (SSR) because Netlify searches for a data-netlify attribute on HTML form tags to setup their Forms backend for you.

Install

Either install with NPM via:

npm install --save react-netlify-forms

or with YARN via:

yarn add react-netlify-forms

Usage

In the following example a contact form with two inputs, a form hidden input for Netlify form handling reCaptcha v2 invisible and a honeypot for extra spam prevention is shown. It also works without JavaScript by falling back to a serverside-rendered form which just submits data with an usual POST request:

My Form

I am using react-dropZone for image uploads to Netlify Forms.

Adding to the form for image upload

enctype="multipart/form-data"

Basic Form

import React, { Component } from 'react'

import { NetlifyForm, Honeypot } from 'react-netlify-forms'

export default ContactForm = () => (
  <NetlifyForm name='Contact' action='/thanks' honeypotName='bot-field'>
    {({ handleChange, success, error }) => (
      <>
        <Honeypot />
        {success && <p>Thanks for contacting us!</p>}
        {error && (
          <p>Sorry, we could not reach our servers. Please try again later.</p>
        )}
        <div>
          <label htmlFor='name'>Name:</label>
          <input type='text' name='name' id='name' onChange={handleChange} />
        </div>
        <div>
          <label htmlFor='message'>Message:</label>
          <textarea
            type='text'
            name='message'
            id='message'
            rows='4'
            onChange={handleChange}
          />
        </div>
        <div>
          <button type='submit'>Submit</button>
        </div>
      </>
    )}
  </NetlifyForm>
)

Form with React dropZone

import React, { useState, useCallback } from 'react'
import { NetlifyForm, Honeypot, Recaptcha } from 'react-netlify-forms'
import styled from 'styled-components'
import {useDropzone} from 'react-dropzone'


const FormInput = styled.input`
  font-family: Kaushan Script,cursive;
  font-size: 1.1em;
  line-height: 1.5em;
  text-size-adjust: 100%;
  width: 45%;
`
const FormTextarea = styled.textarea`
  font-family: Kaushan Script,cursive;
  font-size: 1.1em;
  line-height: 1.5em;
  text-size-adjust: 100%;
  width: 95%;
`

const Title = styled.div`
  font-family: Kaushan Script,cursive;
`;

function Contact() {
  const [file, setFile] = useState({});
  const onDrop = useCallback(acceptedFiles => {
    console.log(acceptedFiles)
    setFile(acceptedFiles[0])
  }, [])
  const {getRootProps, getInputProps, isDragActive} = useDropzone({onDrop})

  return (
    <NetlifyForm
      name='contact'
      honeypotName='bot-field'
      enableRecaptcha
      onSuccess={(response, context) => {
        console.log('Successfully sent form data to Netlify Server')
        context.formRef.current.reset()
      }}
    >
      {({ handleChange, success, error }) => (
        <>
          <div 
            className='box'
          >
            <Honeypot />
            
            {success && (
              <p 
                style={{ 
                  color: '#00FF00', 
                  marginLeft: '2em'
                }}
              >
                Thanks for contacting us!
              </p>
            )}
            {error && (
              <p 
                style={{ 
                  color: '#0000FF',
                  marginLeft: '2em'
                }}
              >
                Sorry, we could not reach servers.
              </p>
            )}
            <div
              style={{
                display: `inline`,
                marginTop: '2em',
                verticalAlign: `middle`,
                justifyItems: `center`,
                justifyContent: `center`,
                alignItems: `center`,
              }}
            >
                <FormInput
                  type='text'
                  name='name'
                  id='name'
                  onChange={handleChange}
                  placeholder='Your Name'
                  className='input'
                  required
                  style={{ 
                    marginTop: '2em',
                  }}
                />                
                  <FormInput
                    type='email'
                    name='email'
                    onChange={handleChange}
                    className='input'
                    placeholder='Email Address'
                    required
                    style={{ 
                      marginTop: '2em',
                    }}              
                  />
            </div>
            <div 
              style={{ 
                marginTop: '2em',
                marginRight: '2em',
                marginLeft: '1.6em',
                justifyItems: `center`,
                justifyContent: `center`,
                alignItems: `center`,
                width: '98%'
              }}
            >
              <FormTextarea
                type='text'
                name='message'
                id='message'
                placeholder='Message'
                onChange={handleChange}
                className='textarea'
                style={{
                  height: '200px',
                  padding: '0.9em',
                  marginBottom: '1.5em'
                }}
                required
              />
            </div>            
            <div               
              style={{
                width: '90%',
                padding: '0.9em',
                marginLeft: '2em',
                marginBottom: '1.5em'
              }}
            >
              <div {...getRootProps()} className='box'>
                <input {...getInputProps()} name='file' />
                  {
                    isDragActive ?
                      <p>Drop the files here ...</p> :
                      <p>Drag 'n' drop some files here, or click to select files</p>
                  }
              </div>
            </div>
            <div 
              style={{ 
                marginBottom: '1em'  
              }}
            >
              <Recaptcha siteKey={ process.env.GATSBY_SITE_RECAPTCHA_KEY } invisible />
              <div 
                style={{ 
                  marginRight: '1em',
                  marginLeft: '2em'  
                }}
              >
                <button type='submit' className='button'>
                  Submit
                </button>
                <button type='reset' className='button'>
                  Reset
                </button>
              </div>
            </div>
          </div>
        </>
      )}
    </NetlifyForm>
  )
}

export default Contact

React dropZone Previews

import React, { useState, useCallback } from 'react'
import { NetlifyForm, Honeypot, Recaptcha } from 'react-netlify-forms'
import styled from 'styled-components'
import Previews from './Previews'

const FormInput = styled.input`
  font-family: Kaushan Script,cursive;
  font-size: 1.1em;
  line-height: 1.5em;
  text-size-adjust: 100%;
  width: 45%;
`
const FormTextarea = styled.textarea`
  font-family: Kaushan Script,cursive;
  font-size: 1.1em;
  line-height: 1.5em;
  text-size-adjust: 100%;
  width: 95%;
`

function Contact() {

  return (
    <NetlifyForm
      name='contact'
      honeypotName='bot-field'
      enableRecaptcha
      enctype="multipart/form-data"
      onSuccess={(response, context) => {
        console.log('Successfully sent form data to Netlify Server')
        context.formRef.current.reset()
      }}
    >
      {({ handleChange, success, error }) => (
        <>
          <div 
            className='box'
          >
            <Honeypot />
            
            {success && (
              <p 
                style={{ 
                  color: '#00FF00', 
                  marginLeft: '2em'
                }}
              >
                Thanks for contacting us!
              </p>
            )}
            {error && (
              <p 
                style={{ 
                  color: '#0000FF',
                  marginLeft: '2em'
                }}
              >
                Sorry, we could not reach servers.
              </p>
            )}
            <input type="hidden" name="form-name" value="contact" />
            <div
              style={{
                display: `inline`,
                marginTop: '2em',
                verticalAlign: `middle`,
                justifyItems: `center`,
                justifyContent: `center`,
                alignItems: `center`,
              }}
            >
                <FormInput
                  type='text'
                  name='name'
                  id='name'
                  onChange={handleChange}
                  placeholder='Your Name'
                  className='input'
                  required
                  style={{ 
                    marginTop: '2em',
                  }}
                />                
                  <FormInput
                    type='email'
                    name='email'
                    onChange={handleChange}
                    className='input'
                    placeholder='Email Address'
                    required
                    style={{ 
                      marginTop: '2em',
                    }}              
                  />
            </div>
            <div 
              style={{ 
                marginTop: '2em',
                marginRight: '2em',
                marginLeft: '1.6em',
                justifyItems: `center`,
                justifyContent: `center`,
                alignItems: `center`,
                width: '98%'
              }}
            >
              <FormTextarea
                type='text'
                name='message'
                id='message'
                placeholder='Message'
                enctype='multipart/form-data'
                onChange={handleChange}
                className='textarea'
                style={{
                  height: '200px',
                  padding: '0.9em',
                  marginBottom: '1.5em'
                }}
                required
              />
            </div>            
            <div               
              style={{
                width: '90%',
                padding: '0.9em',
                marginLeft: '2em',
                marginBottom: '1.5em'
              }}
            >
              <Previews />
            </div>
            <div 
              style={{ 
                marginBottom: '1em'  
              }}
            >
              <Recaptcha siteKey={ process.env.GATSBY_SITE_RECAPTCHA_KEY } invisible />
              <div 
                style={{ 
                  marginRight: '1em',
                  marginLeft: '2em'  
                }}
              >
                <button type='submit' className='button'>
                  Submit
                </button>
                <button type='reset' className='button'>
                  Reset
                </button>
              </div>
            </div>
          </div>
        </>
      )}
    </NetlifyForm>
  )
}

export default Contact

React dropZone Previews Component

import React, {useEffect, useState} from 'react';
import {useDropzone} from 'react-dropzone';

const thumbsContainer = {
  display: 'flex',
  flexDirection: 'row',
  flexWrap: 'wrap',
  marginTop: '1em'
};

const thumb = {
  display: 'inline-flex',
  borderRadius: '4px',
  border: 'thin solid #939799',
  marginBottom: '2em',
  marginRight: '1em',
  width: 'auto',
  height: '100px',
  padding: '1em',
  boxSizing: 'border-box'
};

const thumbInner = {
  display: 'flex',
  minWidth: '0px',
  overflow: 'hidden'
};

const img = {
  display: 'block',
  width: 'auto',
  height: '100%'
};


export default function Previews(props) {
  const [files, setFiles] = useState([]);
  const {getRootProps, getInputProps} = useDropzone({
    accept: 'image/*',
    onDrop: acceptedFiles => {
      setFiles(acceptedFiles.map(file => Object.assign(file, {
        preview: URL.createObjectURL(file)
      })));
    }
  });
  
  const thumbs = files.map(file => (
    <div style={thumb} key={file.name}>
      <div style={thumbInner}>
        <img
          src={file.preview}
          style={img}
        />
      </div>
    </div>
  ));

  useEffect(() => () => {
    // Make sure to revoke the data uris to avoid memory leaks
    files.forEach(file => URL.revokeObjectURL(file.preview));
  }, [files]);

  return (
    <section className="container box">
      <div {...getRootProps({className: 'dropzone'})}>
        <input {...getInputProps()} type='file' name='file' />
        <p>Drag 'n' drop some files here, or click to select files</p>
      </div>
      <aside style={thumbsContainer}>
        {thumbs}
      </aside>
    </section>
  );
}

<Previews />

For more examples please browse website.

License

MIT © Björn Clees


Thanks to create-react-library for providing quick setup for NPM packages.



Comments Are Moderated

Visitor Comments

Title:  Just Can Tell

Date:  22/05/24

Message:  
Ok lets See if this works, this is going to be cool if it pulls data from Netlify to comments.json

Title:  Yes Maybe

Date:  22/05/22

Message:  
Working, and its cool for sure

Sooner Girls

National Champions For the Fifth Time, Go Sooners!

Css Tricks

Front-End UI, Javascript & Functions, HTML Tips, and More!

Fox News

The Truth In the Latest World and National News.