Appearance
Form
Wraps your fields and buttons in a <form> that handles the repeated parts: the required note, focus on a failed submit, a second submit while saving, and the spacing.
vue
<script setup lang="ts">
import { FsButton, FsField, FsForm, FsInput } from '@fivespark/ui'
import { ref } from 'vue'
const naam = ref('')
async function save() {
await new Promise(resolve => setTimeout(resolve, 1000))
}
</script>
<template>
<FsForm class="w-full max-w-md" @submit="save">
<FsField label="Naam">
<FsInput v-model="naam" />
</FsField>
<template #actions>
<FsButton type="submit" variant="primary" label="Opslaan" />
</template>
</FsForm>
</template>Usage
vue
<script setup lang="ts">
import { FsButton, FsField, FsForm, FsInput } from '@fivespark/ui'
import { ref } from 'vue'
const naam = ref('')
function save() {}
</script>
<template>
<FsForm @submit="save">
<FsField label="Naam"><FsInput v-model="naam" /></FsField>
<template #actions>
<FsButton type="submit" variant="primary" label="Opslaan" />
</template>
</FsForm>
</template>@submit is the handler; the browser's own submit is cancelled while it is set. Form does not check values: you decide each Field's error. For a question with two answers, use a Dialog.
Examples
Required fields
required-note says once what the asterisk means. Add it to every form with a required field.
vue
<script setup lang="ts">
import { FsButton, FsField, FsForm, FsInput } from '@fivespark/ui'
import { ref } from 'vue'
const naam = ref('')
const telefoon = ref('')
function save() {}
</script>
<template>
<FsForm required-note class="w-full max-w-md" @submit="save">
<FsField label="Naam" required>
<FsInput v-model="naam" />
</FsField>
<FsField label="Telefoonnummer">
<FsInput v-model="telefoon" type="tel" />
</FsField>
<template #actions>
<FsButton type="submit" variant="primary" label="Opslaan" />
</template>
</FsForm>
</template>Validation
Set the errors in your handler. When a submit leaves a field with an error, focus moves to the first one, and its message is read out.
vue
<script setup lang="ts">
import { FsButton, FsField, FsForm, FsInput } from '@fivespark/ui'
import { reactive } from 'vue'
const values = reactive({ naam: '', email: '' })
const errors = reactive<Record<string, string | undefined>>({})
function save() {
errors.naam = values.naam.trim() ? undefined : 'Vul een naam in'
errors.email = values.email.includes('@') ? undefined : 'Vul een e-mailadres in, zoals naam@bedrijf.nl'
}
</script>
<template>
<FsForm required-note class="w-full max-w-md" @submit="save">
<FsField label="Naam" required :error="errors.naam">
<FsInput v-model="values.naam" />
</FsField>
<FsField label="E-mailadres" required :error="errors.email">
<FsInput v-model="values.email" type="email" />
</FsField>
<template #actions>
<FsButton type="submit" variant="primary" label="Opslaan" />
</template>
</FsForm>
</template>Saving
Return a promise from the handler. pending is true until it settles, and a second submit is ignored meanwhile. Pass it to the submit button's loading.
vue
<script setup lang="ts">
import { FsButton, FsField, FsForm, FsInput } from '@fivespark/ui'
import { ref } from 'vue'
const naam = ref('Jansen Bouw B.V.')
async function save() {
await new Promise(resolve => setTimeout(resolve, 2000))
}
</script>
<template>
<FsForm class="w-full max-w-md" @submit="save">
<FsField label="Naam">
<FsInput v-model="naam" />
</FsField>
<template #actions="{ pending }">
<FsButton type="submit" variant="primary" :loading="pending" label="Opslaan" loading-text="Klant opslaan…" />
<FsButton label="Annuleren" to="/klanten" />
</template>
</FsForm>
</template>Without a handler
Without @submit, the browser submits the form to its action. Give each control a name.
vue
<script setup lang="ts">
import { FsButton, FsField, FsForm, FsInput } from '@fivespark/ui'
</script>
<template>
<FsForm action="/zoeken" method="get" class="w-full max-w-md">
<FsField label="Offertenummer">
<FsInput name="nummer" />
</FsField>
<template #actions>
<FsButton type="submit" variant="primary" label="Zoeken" />
</template>
</FsForm>
</template>API Reference
FsForm
| Prop | Type | Default | Description |
|---|---|---|---|
requiredNote | boolean | false | Shows "Velden met een * zijn verplicht." or "Fields marked * are required." first. Set it on a form with a required field. |
onSubmit | ((event: SubmitEvent) => unknown) | The submit handler, written `@submit`. The browser's submit is cancelled, a second submit is ignored while its promise is pending, and afterwards the first invalid field is focused. Without it, the browser submits the form to its `action`. |
| Slot | Props | Description |
|---|---|---|
default | { pending: boolean; } | The fields. `pending` is true while the submit handler's promise is. |
actions | { pending: boolean; } | The buttons, in a row after the fields: the submit button first, with `:loading="pending"`. |