Framework Snippets
Ready-to-use code for every major frontend framework and language.
The Setup tab generates a complete, copy-pasteable code snippet for your chosen framework. Switch tabs to get the code tailored to your stack — it updates live as you add, remove, or reorder fields.
Supported frameworks
HTML · React · Next.js · Remix · Gatsby · Vue · Nuxt · Astro · Svelte · SvelteKit · Angular · jQuery · Alpine.js · HTMX · PHP · Laravel
HTML
The simplest integration. Just a <form> tag pointing at your endpoint.
<form action="https://api.nbforms.com" method="POST">
<input type="hidden" name="_token" value="YOUR_FORM_TOKEN" />
<label>Name</label>
<input type="text" name="name" required />
<label>Email</label>
<input type="email" name="email" required />
<label>Message</label>
<textarea name="message" required></textarea>
<button type="submit">Send</button>
</form>Works in any static site, WordPress, Webflow, Framer, or anything that renders HTML.
React / Next.js / Remix / Gatsby
These snippets intercept the submit event with fetch so the page does not reload. They manage a status state (idle | sending | success | error) and disable the submit button while sending.
// React example
import { useState } from 'react'
export default function ContactForm() {
const [status, setStatus] = useState('idle')
async function handleSubmit(e) {
e.preventDefault()
setStatus('sending')
const res = await fetch('https://api.nbforms.com', {
method: 'POST',
body: new FormData(e.target),
})
setStatus(res.ok ? 'success' : 'error')
}
if (status === 'success') return <p>Thanks! We'll be in touch soon.</p>
return (
<form onSubmit={handleSubmit} data-nbf="YOUR_FORM_ID">
<input type="hidden" name="_token" value="YOUR_FORM_TOKEN" />
{/* your fields */}
<button type="submit" disabled={status === 'sending'}>
{status === 'sending' ? 'Sending…' : 'Send'}
</button>
</form>
)
}Next.js adds 'use client' at the top. Remix uses <Form> from @remix-run/react and a server-side action function.
Vue / Nuxt
<template>
<p v-if="success">Thanks! We'll be in touch soon.</p>
<form v-else @submit.prevent="submit" data-nbf="YOUR_FORM_ID">
<input type="hidden" name="_token" value="YOUR_FORM_TOKEN" />
<!-- your fields -->
<button type="submit" :disabled="sending">
{{ sending ? 'Sending…' : 'Send' }}
</button>
</form>
</template>
<script setup>
const sending = ref(false)
const success = ref(false)
async function submit(e) {
sending.value = true
const res = await fetch('https://api.nbforms.com', {
method: 'POST',
body: new FormData(e.target),
})
success.value = res.ok
sending.value = false
}
</script>Astro
Astro forms use a vanilla JS event listener in a <script> block. The form can use a standard action attribute as a fallback.
---
---
<form id="nbform" action="https://api.nbforms.com" method="POST" data-nbf="YOUR_FORM_ID">
<input type="hidden" name="_token" value="YOUR_FORM_TOKEN" />
<!-- your fields -->
<button type="submit">Send</button>
<p id="success" hidden>Thanks! We'll be in touch soon.</p>
</form>
<script>
const form = document.getElementById('nbform')
form.addEventListener('submit', async (e) => {
e.preventDefault()
const btn = form.querySelector('button[type=submit]')
btn.disabled = true
btn.textContent = 'Sending…'
const res = await fetch(form.action, { method: 'POST', body: new FormData(form) })
if (res.ok) document.getElementById('success').hidden = false
btn.disabled = false
btn.textContent = 'Send'
})
</script>PHP
The PHP snippet submits from the server side using file_get_contents with a stream context, then re-renders the page with a success state.
Alpine.js
Alpine.js handles the state inline using x-data:
<div x-data="{ sending: false, success: false }">
<p x-show="success">Thanks! We'll be in touch soon.</p>
<form x-show="!success" data-nbf="YOUR_FORM_ID"
@submit.prevent="
sending = true;
fetch('https://api.nbforms.com', { method: 'POST', body: new FormData($el) })
.then(r => { success = r.ok; sending = false })
">
<input type="hidden" name="_token" value="YOUR_FORM_TOKEN" />
<!-- your fields -->
<button type="submit" :disabled="sending"
x-text="sending ? 'Sending…' : 'Send'"></button>
</form>
</div>HTMX
HTMX uses hx-post to submit the form and swap the response HTML into the target element.
<div id="contact-wrapper">
<form hx-post="https://api.nbforms.com"
hx-target="#contact-wrapper"
hx-swap="innerHTML"
data-nbf="YOUR_FORM_ID">
<input type="hidden" name="_token" value="YOUR_FORM_TOKEN" />
<!-- your fields -->
<button type="submit">Send</button>
</form>
</div>The NBForms endpoint returns { "success": true } — configure your HTMX response handling accordingly, or use the redirect setting to send users to a thank-you page.
Notes
- All snippets include a
data-nbfattribute on<form>scoped to the form ID. This is used by the optional pixel tracker and for CSS scoping. - The
_tokenhidden input is mandatory in every snippet — remove it and submissions will fail. - The Setup tab generates the CSS style block for the chosen theme automatically. Copy Full HTML to get the complete standalone file including styles.