A contact form without a server, saving to your own database
A contact form without a server to run. One route checks each message and saves it as a row in your own Supabase table. It works without JavaScript, and its key can add rows and nothing else.
You want a contact form, not a dashboard to read it in
This one saves each message to a table in your own Supabase project. You read them in Supabase's Table Editor, and you can give your client a seat there too. We never hold the messages.
The whole template is public. Read it before you trust it.
Or scaffold it
$ npx wawesome init --template contact-form
$ npx wawesome deployWhat you get
A Function called root. The page is a plain file, public/index.html, with a
form and no script. The form posts to the page’s own address, where one
Hono route in src/index.ts checks the message with
zod:
const Enquiry = z.object({
name: z.string().trim().min(1, "Enter your name.").max(200, "Keep your name to 200 characters."),
email: z.string().trim().pipe(z.email("Enter an email address like name@example.com.").max(320)),
message: z.string().trim().min(1, "Enter a message.").max(5000, "Keep your message to 5000 characters."),
});
A good message becomes a row, and the visitor gets a 303 to the thank-you
note. A wrong field gets a 422 that names it. If Supabase refuses the row, the
answer is a 500 and the reason is in your logs.
Run it
npx wawesome init --template contact-form
It offers to log you in if you aren’t. Then it asks for a Function name, root
by default, and an App slug. If you haven’t deployed yet, it offers to change
your workspace address, which locks at your first deploy. Then it asks for two
values, both in your Supabase project settings:
SUPABASE_URL, the project’s URL. We open that one host to your App’s outbound calls.SUPABASE_PUBLISHABLE_KEY, the key that starts withsb_publishable_. It isn’t a secret, becauseschema.sqllets it add rows and nothing else.
Leave both blank and the page still goes live, and the form answers that it has
no database yet. Set them later with npx wawesome env set.
Before the form can save anything, run schema.sql in your project’s SQL
Editor. Then send a message and open Table Editor → enquiries. The row is there.
What to change first
The words in public/index.html. To add a field, add an input to the page, a
rule to the zod schema, and a column to schema.sql.
What it doesn’t do
There’s no spam protection and no rate limit. Anyone with the publishable key can add rows directly, without the route’s checks. It doesn’t email you when a message arrives.
- form
- contact
- database
- supabase
- hono
- zod
- website
- typescript
Ready in about a minute
Sign in with GitHub, deploy, and get a public HTTPS endpoint.