Forms
Files: src/config/config.toml, src/content/contact/english/-index.md, src/content/auth/english/ · Skill level: Beginner
Kivo is a static site, so its forms send data to a service you choose. There are three kinds:
| Form | Where it appears | Sends to |
|---|---|---|
| Contact form | /contact/ | Formsubmit, Formspree, or Netlify Forms |
| Newsletter forms | Blog pages, /status/, changelog, the hero form layout, the CTA newsletter layout, the large footer | Mailchimp |
| Log in, sign up, reset | /login/, /signup/, /forgot-password/ | Your own app (Kivo ships no account system) |
Until an endpoint is set, npm run dev shows a warning inside each form, and npm run dev and npm run build print one in the terminal. Visitors never see these warnings.
Connect The Contact Form
Pick a provider and set both lines in config.toml:
Free, no account needed. Messages arrive by email.
[settings] contactFormProvider = "formsubmit.co"The first message you send triggers an activation email from Formsubmit. Open it and confirm, or later messages won’t be delivered.
Create a form at formspree.io and copy its endpoint.
[settings] contactFormAction = "https://formspree.io/f/your-form-id" contactFormProvider = "formspree"Only when the site is hosted on Netlify. Netlify detects the form at deploy time.
[settings] contactFormAction = "/" contactFormProvider = "netlify"Turn on form detection in the Netlify dashboard (Forms), deploy, and send a test message. Submissions appear in the dashboard and can be forwarded by email. Check that your test message arrives there before you rely on the form.
After launch, send one real message from the live site to make sure it arrives.
Change The Contact Form Fields
The fields of the /contact/ form are in the contact page’s file, src/content/contact/english/-index.md, under contactSection.form.inputs. (src/content/sections/english/contact-section.md holds defaults, but the page file sets its own list, and a list in a page block replaces the default list.)
contactSection: form: emailSubject: "New message from the website" # subject of the email you receive submitButton: enable: true label: "Contact sales" inputs: - label: "Work email" name: "Email" # the field name in the message you receive type: "email" required: true halfWidth: true # two fields per row on large screens - label: "Team size" name: "Team Size" dropdown: type: "select" # select | search (a searchable list) items: - label: "1–10 engineers" value: "1-10" - label: "How can we help?" name: "Message" tag: "textarea" rows: "4" required: true| Field type | How to write it |
|---|---|
| Text | No type, or type: "text" |
| Email, phone, URL, number, date | type: "email", "tel", "url", "number", "date" |
| Long text | tag: "textarea" and rows |
| Dropdown | dropdown: with type and items |
| Radio buttons or checkboxes | type: "radio" or "checkbox" with items, and a groupLabel |
Other options: required, halfWidth, and defaultValue.
The last two items of inputs are not fields: the one with note: success holds the message shown after a message is sent, and the one with note: deprecated the message shown when sending fails. Edit their content to change the wording:
- note: success parentClass: "hidden text-sm message success" content: "Thanks. We will reply within one business day." - note: deprecated parentClass: "hidden text-sm message error" content: "Something went wrong. Please try again or email us."The note under the whole form (form.note) accepts Markdown, for a privacy policy link.
The contact details beside the form come from [settings.contactInfo] in config.toml.
The contact page file has no schema, so npm run astro-check doesn’t report a mistyped option there. Open /contact/ after each change and send a test message.
Connect The Newsletter (Mailchimp)
-
In Mailchimp, open Audience → Signup forms → Embedded forms.
-
In the embed code, find
<form action="...">and copy the URL. It looks likehttps://xxxx.us1.list-manage.com/subscribe/post?u=...&id=.... -
Paste it into
config.toml, then change every&to a plain&:[settings.subscription]enable = trueformAction = "https://xxxx.us1.list-manage.com/subscribe/post?u=abc123&id=def456&f_id=0012ab" -
Optional:
mailchimpTagValueadds a Mailchimp tag to every new subscriber, so you can tell where they came from. -
After you deploy, subscribe once with a test address and check that it appears in your Mailchimp audience.
The newsletter forms post to Mailchimp only. To use another email service, the form component needs a code change.
The form title, note, button, and messages are in subscription in src/i18n/en.json and fr.json. enable = false removes every newsletter form at once; layouts that use one (the hero form layout and the CTA newsletter layout) show a button or the install command instead.
Log In, Sign Up, And Reset Password
These are screens only: they look like a real app’s account pages and post to the address you give them. Kivo has no user accounts. Connect them to your app, or point the header links straight at your app’s own login page.
Each screen has a file in src/content/auth/english/ (login.md, signup.md, forgot-password.md):
options: layout: "default" # default (split screen with a side panel) | centered (one card)
providers: # "Continue with..." buttons - enable: true label: "Continue with GitHub" icon: "/images/icons/github.svg" url: "https://app.example.com/auth/github"
form: action: "https://app.example.com/session" # where the form posts; "#" shows a dev warning method: "post" fields: - name: "email" type: "email" label: "Email" autocomplete: "email" required: true submitLabel: "Log in"
aside: # the right-hand panel in the default layout enable: true quote: "..."The auth screens are hidden from search engines and the sitemap, and they hide the site header and footer.
Do It With AI
Connect my forms. Contact form: [Formsubmit with EMAIL | Formspree with ID | Netlify Forms]; setcontactFormAction and contactFormProvider in src/config/config.toml following its comments.Newsletter: here is my Mailchimp embed form action: [URL]; set [settings.subscription] formAction andreplace every & with &. Then change the contact form fields insrc/content/contact/english/-index.md (and french/) to: [FIELDS].