Enquiry form
Label above field, one clear primary action, errors stated in words — the form column, composed entirely from system pieces.
What it is made of
GdCardat--gd-size-form— the single columnGdField— the label, the hint and the error, wired to the controlGdInput,GdSelect,GdCheckbox— the controlsGdButtonvariant="primary"block, plus a ghost way out
The sign-in card and the document-upload card are their own blocks — Sign-in and Document upload.
The block
Lodge an enquiry
Tell us about the property and what you're planning.
Enter a full email address so we can reply.
Code
<GdCard class="form-card"> <!-- max-width: var(--gd-size-form) -->
<GdField v-slot="f" label="Property address">
<GdInput v-bind="f" v-model="address" />
</GdField>
<div class="pair"> <!-- ONE fact, two controls -->
<GdField v-slot="f" label="Lot size">
<GdInput v-bind="f" v-model="lotSize">
<template #trailing>m²</template>
</GdInput>
</GdField>
<GdField v-slot="f" label="Project type">
<GdSelect v-bind="f" v-model="project" :options="TYPES" />
</GdField>
</div>
<GdField v-slot="f" label="Email" :error="emailErr">
<GdInput v-bind="f" v-model="email" type="email" />
</GdField>
<GdCheckbox v-model="wantsReport">Email me the full planning report.</GdCheckbox>
<GdButton variant="primary" block :loading="submitting" loading-label="Submitting…">
Submit enquiry
</GdButton>
<GdButton variant="ghost">Cancel</GdButton>
</GdCard>Rules
- Single column,
--gd-size-form(520px) max. Two fields share a row only when they are ONE fact — a number and its unit, a month and a year, a lot size and a project type entered together. - Never use a placeholder as a label.
GdFieldowns the label and wires the hint and error to the control. - Write the error as a sentence a person can act on — “Enter a full email address so we can reply”, not “Invalid input”.
- One primary action per form, and it says what it does — “Submit enquiry”, never “OK”.
- Go busy, do not merely disable, while the form is in flight. Pass
loadingandloading-label. - Collapse the paired row to one column below 600px. Two controls at half a phone's width are two controls nobody can use.
Behavior & Anatomy
Why the busy button rather than a disabled one
A button that says “Sending…” explains itself and a grey one does not. Disabling is the cheaper thing to write and the more expensive thing to receive: it removes the control from the keyboard, says nothing about what is happening, and leaves the user with no way to ask.
Why two fields may share a row only when they are one fact
A row is a visual claim that the things in it belong together. Lot size and project type are being entered as one statement about the proposal, so the row is true. Two unrelated fields side by side make the same claim falsely, and the reader has to undo it before they can answer either one.
Why the error is a sentence
“Invalid input” names the system's problem. “Enter a full email address so we can reply” names the user's next action and the reason for it — and the reason is what makes the field worth filling in properly rather than defeating.