Forms
Files: src/config/config.toml, form fields in content files · Skill level: Beginner
Homio is a static site: it has no server of its own to receive messages. Each form sends its answers to a form service you choose, which emails them to you or keeps them in a dashboard. You set that service once in config.toml.
The Forms And Where They Send
| Form | Where it appears | Fields are in | Sends to |
|---|---|---|---|
| Contact | /contact/, the quote contact on the main homepage | src/content/sections/english/contact-section.md (or a page’s contactSection block) | contactFormAction |
| Walkthrough request | /industries/, industry pages, commercial homepage and service pages | the page’s contactSection block | contactFormAction |
| Gift card and referral requests | /gift-cards/, /referral/ | contactSection in pages/english/gift-cards.md and referral.md | contactFormAction |
| Job application | job pages, optionally /careers/#apply | application.form in careers/english/-index.md | contactFormAction |
| Hero quote form | heroes with the form layout (/home-cleaning/) | form in the heroSection block | contactFormAction |
| Booking request | /book/, and the booking card on /home-cleaning/ | src/content/sections/english/booking-section.md | [settings.booking] formAction, else contactFormAction |
| Newsletter signup | blog pages, default and large footers, CTA newsletter layout | subscription in src/i18n/en.json | [settings.subscription] formAction (Mailchimp) |
Every form except the newsletter uses the same provider, contactFormProvider. The booking form has its own guide: Booking Request.
Connect The Forms
The theme ships with placeholder addresses. Until you replace them, messages go nowhere: npm run dev shows a yellow warning inside each form, and both npm run dev and npm run build print a [forms] warning in the terminal. Visitors of a deployed site never see the notice, so check the terminal before you deploy.
Pick a provider and set both lines in [settings] of config.toml:
Free, no account. Messages arrive by email as a table.
[settings] contactFormProvider = "formsubmit.co"The first message 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. Messages appear in your Formspree dashboard, and Formspree can email them to you.
[settings] contactFormAction = "https://formspree.io/f/your-form-id" contactFormProvider = "formspree"Only when the site is hosted on Netlify. Netlify detects the forms 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.
Booking requests to another inbox. Leave formAction = "" in [settings.booking] to send bookings with the contact form, or set your own address (same provider) to keep them apart:
[settings.booking]After launch, send one real message from each form on the live site to make sure it arrives.
The Newsletter (Mailchimp)
- In Mailchimp, open Audience → Signup forms → Embedded forms, and copy the URL in
<form action="...">from the embed code. - Paste it as
formActionin[settings.subscription]ofconfig.toml, in place of the placeholder withYOUR_USER_IDandYOUR_LIST_ID. - The embed code writes
&between parameters: change each one to a plain&. The dev server warns if one is left.
[settings.subscription] enable = true # false hides every signup form and the newsletter section formAction = "https://your-account.us1.list-manage.com/subscribe/post?u=YOUR_USER_ID&id=YOUR_LIST_ID&f_id=YOUR_FORM_ID" mailchimpTagValue = "" # optional Mailchimp tag id added to every signupMailchimp’s bot field is added for you from the u and id in the URL. The form’s messages (sending, success, already subscribed, errors) and its title and consent line are in subscription of src/i18n/en.json and fr.json. title and note in [settings.subscription] replace them on a single-language site.
Change The Fields
Every form except the booking form and the newsletter is written the same way: a form with an emailSubject, a submitButton, an optional note, and a list of inputs. For the contact page, edit form in src/content/sections/english/contact-section.md (and french/):
form: emailSubject: "New message from the website" # subject of the email the provider sends you submitButton: enable: true label: "Send message" # Shown under the button. {phone} {email} {name} come from [business] note: "We use your details only to reply. [Privacy policy](/privacy-policy/)" inputs: - label: "Name" name: "Name" # the field name in the message you receive placeholder: "Your name" required: true halfWidth: true # two fields per row on wider screens - label: "Message" name: "Message" tag: "textarea" rows: "5" required: true| Field type | How to write it |
|---|---|
| Text | No type, or type: "text" |
| Email, phone, number, date, web address | type: "email", "tel", "number", "date", or "url" |
| Long text | tag: "textarea" and rows |
| Radio buttons | type: "radio", one item per choice, with the same name and group; the first carries groupLabel (the question) |
| Checkboxes | type: "checkbox", one item per choice, with a shared group |
| Dropdown | dropdown: with type (select or search) and items (label, value, optional selected and hint). source: "areas" adds one option per service area |
Other options: placeholder, required, defaultValue, value, checked, and id. The full list is inputFieldSchema in src/sections.schema.ts. A dropdown item’s hint shows a line of Markdown under the field while it is chosen, as the “An existing booking” topic does.
The job application can put {role} and {area} in its emailSubject, and sends the role in a hidden field. The gift card form adds the chosen amount to its subject.
Success And Error Messages
The last two items of inputs are not fields. The one with note: success holds the message shown after a message is sent; the one with note: deprecated the message shown when sending fails. Edit their content and keep their parentClass:
- note: success parentClass: "hidden text-sm message success" content: "Thanks. We reply the same working day, usually by phone." # sample promise - note: deprecated parentClass: "hidden text-sm message error" content: "That didn't send. Call {phone} or email {email}." # {phone} {email} from [business]{phone} and {email} are filled in from [business] in config.toml. Make the success message a promise you keep. Field error messages (“Check this field.”) are in form of src/i18n/en.json; the booking form’s messages are in booking-section.md (success) and booking of the i18n files.
Without JavaScript, every form still sends: it posts straight to the provider, which shows its own confirmation page. Booking requests sent this way land on /book/thanks/ (thankYouUrl in [settings.booking]).
Spam Protection
Every form except the newsletter has two built-in traps, with no captcha to solve (the newsletter uses Mailchimp’s own hidden bot field):
- A hidden field that people never see but bots fill in. Its name matches your provider:
_honey(Formsubmit),_gotcha(Formspree), orbot-field(Netlify). - A time trap: a form sent less than 4 seconds after the visitor first touched it is dropped without a request.
Your provider may filter spam on top of this: check its settings and documentation.
Privacy
Each form’s note links to your privacy policy, and the booking form has a consent checkbox (consent in booking-section.md). Keep them, point the links at your real pages, and list your form provider in src/content/pages/english/privacy-policy.md.
The section files have no schema, so npm run astro-check doesn’t report a mistyped option there. Open each form, fill it in, and send a test after each change.
Do It With AI
Connect my forms to [Formsubmit with EMAIL | Formspree with form ID | Netlify Forms]: setcontactFormAction and contactFormProvider in src/config/config.toml following its comments, and[leave [settings.booking] formAction empty | set it to BOOKING ENDPOINT]. Set the Mailchimp URL[URL] as formAction in [settings.subscription], with every & changed to &. Then run npm run devand tell me if any [forms] warning is left.Change the contact form in src/content/sections/english/contact-section.md (and french/) to askfor: [FIELDS]. Keep the form structure, the note with the privacy link, and the two message itemsat the end of inputs (note: success and note: deprecated). Use {phone} and {email} in the errormessage.