> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pipedform.com/llms.txt
> Use this file to discover all available pages before exploring further.

# React

Build a basic contact form in React that submits directly to PipedForm using `fetch`, with simple state management for handling submission status.

## Basic Example

```tsx theme={null}
type Status =
  | { status: 'idle' }
  | { status: 'loading' }
  | { status: 'error'; message: string }
  | { status: 'success'; message: string };

function BasicExample() {
  const [status, setStatus] = useState<Status>({ status: 'idle' });

  const onSubmit = async (e: React.SubmitEvent<HTMLFormElement>) => {
    e.preventDefault();

    setStatus({ status: 'loading' });

    const formDataJson = JSON.stringify(
      Object.fromEntries(new FormData(e.currentTarget)),
    );

    const res = await fetch(
      'https://pipedform.com/f/{form_id}',
      {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: formDataJson,
      },
    );

    const data = await res.json();

    if (!res.ok) {
      setStatus({ status: 'error', message: data.message });
    } else {
      setStatus({ status: 'success', message: 'Form submitted successfully' });
    }
  };

  return (
    <form onSubmit={onSubmit}>
      <input name="name" placeholder="John" />
      <input name="email" type="email" placeholder="john@gmail.com" />
      <textarea name="message" placeholder="Enter your message..." />

      {status.status === 'error' && (
        <p style={{ color: 'red' }}>{status.message}</p>
      )}
      {status.status === 'success' && (
        <p style={{ color: 'green' }}>{status.message}</p>
      )}

      <button type="submit" disabled={status.status === 'loading'}>
        {status.status === 'loading' ? 'Loading...' : 'Send'}
      </button>
    </form>
  );
}
```
