Form fields
Form fields provides a way to build forms using configuration.
Examples
<script>
const required = (failMessage) => (val) =>
val !== '' && val !== null && val !== undefined ? '' : failMessage;
const mapToNumber = (x) => Number(x || 0);
export default {
data() {
return {
items: ['Pizza', 'Keyboards', 'Guitars', 'Rocket ships'].map((text) => ({
text,
value: text,
})),
fields: {
USERNAME: {
label: 'NAME (ALL CAPS)',
mapValue: (x) => (x ? x.toUpperCase() : x),
validators: [required('NAME IS REQUIRED!!!')],
},
password: {
label: 'Password with group styling',
inputAttrs: { type: 'password' },
groupAttrs: { class: 'gl-bg-purple-50 gl-w-20' },
validators: [required('Password is required')],
},
confirmPassword: {
label: 'Confirm Password',
inputAttrs: { type: 'password' },
validators: [required('Confirmed password is required')],
},
custom: {
label: 'Custom input',
mapValue: mapToNumber,
validators: [(val) => (val < 1 ? 'Please click this at least once :)' : '')],
},
favoriteItem: {
label: 'Favorite Item',
groupAttrs: {
optional: true,
'optional-text': '(optional)',
},
},
favoriteFood: {
label: 'Favorite Food',
fieldset: true,
groupAttrs: {
optional: true,
'optional-text': '(select all that apply)',
},
validators: [
(val) => (!val || val.length === 0 ? 'Please select at least one option' : ''),
],
},
acknowledge: {
label: null,
validators: [(val) => (val === true ? '' : 'Acknowledge before submitting!')],
},
},
formValues: {},
testFormId: 'form_fields_story',
serverValidations: {},
loading: false,
foodOptions: [
{ text: 'Burgers', value: 'Burgers' },
{ text: 'Pizza', value: 'Pizza' },
{ text: 'Sushi', value: 'Sushi' },
],
};
},
created() {
this.fields.confirmPassword.validators.push(
(confirmValue) => (confirmValue !== this.formValues.password ? 'Must match password' : '')
);
},
computed: {
values() {
const { confirmPassword, ...rest } = this.formValues;
return rest;
},
valuesJSON() {
return JSON.stringify(this.values, (key, value) => (value === undefined ? null : value), 2);
},
favoriteItemToggleText() {
if (!this.formValues.favoriteItem) {
return 'Select an item';
}
return null;
},
},
methods: {
onInputField({ name }) {
this.$delete(this.serverValidations, name);
},
async onSubmit() {
this.loading = true;
await new Promise((resolve) => {
setTimeout(resolve, 1000);
});
this.loading = false;
if (this.formValues.USERNAME === 'FOO') {
this.$set(this.serverValidations, 'USERNAME', 'Username has already been taken.');
return;
}
this.$refs.modal.show();
},
},
};
</script>
<template>
<div>
<h3>Fields</h3>
<form :id="testFormId" @submit.prevent>
<gl-form-fields
:fields="fields"
v-model="formValues"
:form-id="testFormId"
:server-validations="serverValidations"
validate-on-blur
@input-field="onInputField"
@submit="onSubmit"
>
<template #group(confirmPassword)-label>
<div class="gl-flex gl-items-center gl-gap-x-3">
<span>Confirm Password</span>
<gl-icon name="information-o" />
</div>
</template>
<template #group(confirmPassword)-description>
Description using <code>group(confirmPassword)-description</code> slot.
</template>
<template #after(confirmPassword)>
<gl-alert class="gl-mb-5" :dismissible="false"
>Custom content using <code>after(confirmPassword)</code> slot.</gl-alert
>
</template>
<template #input(custom)="{ id, value, input, blur }">
<button :id="id" @click="input(value + 1)" @blur="blur" type="button">{{ value }}</button>
</template>
<template #input(favoriteItem)="{ id, value, input, blur }">
<gl-listbox
:toggle-id="id"
:items="items"
:selected="value"
:toggle-text="favoriteItemToggleText"
@select="input"
@hidden="blur"
/>
</template>
<template #group(favoriteItem)-label-description>
Label description using <code>group(favoriteItem)-label-description</code> slot.
</template>
<template #input(favoriteFood)="{ id, value, input, validation }">
<gl-form-checkbox-group
:id="id"
:options="foodOptions"
:checked="value || []"
:state="validation.state"
@input="input"
/>
</template>
<template #input(acknowledge)="{ id, input, validation, value }">
<gl-form-checkbox :state="validation.state" :id="id" :checked="value" @input="input">
I accept the terms and conditions
</gl-form-checkbox>
</template>
</gl-form-fields>
<gl-button type="submit" category="primary" :loading="loading">Submit</gl-button>
</form>
<gl-modal ref="modal" modal-id="submission-modal" title="Form submission"
><pre>{{ valuesJSON }}</pre></gl-modal
>
</div>
</template>Structure
Guidelines
Appearance
Behavior
Accessibility
Code reference
Usage
GlFormFields provides form builder functionality for ease of building simple
forms out of other GitLab UI form components.
For a code example, look at the story. It covers usage of mapValue, validators,
custom form elements, and inputAttrs.
Fields type
Each value of fields prop is expected to be a FieldDefinition. See below for the shape of this type:
interface FieldDefinition<TValue> {
// Label text to show for this field.
// When explicitly set to null, the label is suppressed.
// When undefined or not provided, the field name is used as the label.
label?: string | null;
// Collection of validator functions
validators?: Array<(value: TValue) => string | undefined>;
// Function that maps the inputted string value to the field's actual value
// (e.g. a Number).
mapValue?: (input: string) => TValue;
// Properties that are passed to the actual input for this field.
inputAttrs?: {};
// Properties that are passed to the group wrapping this field.
groupAttrs?: {};
// When true, renders the form group as a fieldset with legend instead of div with label.
fieldset?: boolean;
}Label behavior
label: "Custom Label"- Renders the provided labellabel: null- Suppresses the label (no label rendered)label: undefinedor not provided - Uses the field name as the label (default behavior)
Slots
| Name | Description |
|---|---|
input(<fieldName>) | Used to render components other than GlFormInput. |
group(<fieldName>)-label | Used for label slot on GlFormGroup of a specific field. |
group(<fieldName>)-description | Used for description slot on GlFormGroup of a specific field. |
group(<fieldName>)-label-description | Used for label-description slot on GlFormGroup of a specific field. |
after(<fieldName>) | Used to render content after GlFormGroup of a specific field. |
GlFormFields
import { GlFormFields } from '@gitlab/ui'; Props
Name | Description | Default |
|---|---|---|
|
| — |
|
| — |
|
| — |
|
|
|
|
|
|
Slots
Name | Description |
|---|---|
slotName | Can be used to pass slots to `GlFormGroup`. |
field.inputSlot.slotName | Scoped slot that can be used for components other than `GlFormInput`. The name of the slot is `input(<fieldName>)`. |
field.afterSlotName | Can be used to add content the form group of a field. The name of the slot is `after(<fieldName>)`. |
Events
Name | Description |
|---|---|
input |
|
field-validation |
|
input-field |
|
submit |
|
Last updated at: