VfMatrix
Basic
The default mode is 'auto', which renders a text input in each cell. Rows are group containers and columns define the fields within each row. The matrix value is an object where keys are row values and values are nested objects with column values as keys and the cell input values as values.
<VfMatrix
name="budget"
:cols="['Q1', 'Q2']"
:rows="['Marketing', 'Engineering']"
/><template>
<VfMatrix
name="budget"
:cols="['Q1', 'Q2']"
:rows="['Marketing', 'Engineering']"
/>
</template><script setup lang="ts">
import { defineSchema, useForm } from '@vueform/ui'
const schema = defineSchema({
budget: {
type: 'matrix',
cols: ['Q1', 'Q2'],
rows: ['Marketing', 'Engineering'],
},
})
const [Form] = useForm({ schema })
</script>
<template>
<Form />
</template>Single Mode
The mode="single" turns each row into a radio group where only one column value can be selected per row. The matrix value is an object where keys are row values and each value is the selected column's value.
<VfMatrix
name="satisfaction"
:cols="['Poor', 'Fair', 'Good', 'Excellent']"
:rows="['Price', 'Quality']"
mode="single"
/><template>
<VfMatrix
name="satisfaction"
:cols="['Poor', 'Fair', 'Good', 'Excellent']"
:rows="['Price', 'Quality']"
mode="single"
/>
</template><script setup lang="ts">
import { defineSchema, useForm } from '@vueform/ui'
const schema = defineSchema({
satisfaction: {
type: 'matrix',
cols: ['Poor', 'Fair', 'Good', 'Excellent'],
rows: ['Price', 'Quality'],
mode: 'single',
},
})
const [Form] = useForm({ schema })
</script>
<template>
<Form />
</template>Multiple Mode
The mode="multiple" turns each row into a checkbox group where multiple column values can be selected per row. The matrix value is an object where keys are row values and each value is an array of selected column values.
<VfMatrix
name="permissions"
:cols="['Create', 'Read', 'Update']"
:rows="['Admin', 'Editor']"
mode="multiple"
/><template>
<VfMatrix
name="permissions"
:cols="['Create', 'Read', 'Update']"
:rows="['Admin', 'Editor']"
mode="multiple"
/>
</template><script setup lang="ts">
import { defineSchema, useForm } from '@vueform/ui'
const schema = defineSchema({
permissions: {
type: 'matrix',
cols: ['Create', 'Read', 'Update'],
rows: ['Admin', 'Editor'],
mode: 'multiple',
},
})
const [Form] = useForm({ schema })
</script>
<template>
<Form />
</template>Plain Object
The rows and cols props also accept a plain object where keys are used as values and values as labels.
<VfMatrix
name="availability"
:cols="{
fri: 'Friday',
sat: 'Saturday',
sun: 'Sunday',
}"
:rows="{
morning: 'Morning',
afternoon: 'Afternoon',
evening: 'Evening'
}"
/><template>
<VfMatrix
name="availability"
:cols="{
fri: 'Friday',
sat: 'Saturday',
sun: 'Sunday',
}"
:rows="{
morning: 'Morning',
afternoon: 'Afternoon',
evening: 'Evening'
}"
mode="multiple"
/>
</template><script setup lang="ts">
import { defineSchema, useForm } from '@vueform/ui'
const schema = defineSchema({
availability: {
type: 'matrix',
cols: {
fri: 'Friday',
sat: 'Saturday',
sun: 'Sunday',
},
rows: {
morning: 'Morning',
afternoon: 'Afternoon',
evening: 'Evening'
},
mode: 'multiple',
},
})
const [Form] = useForm({ schema })
</script>
<template>
<Form />
</template>Array of Objects
The rows and cols props can also be an array of objects. Each object's value property is used as the value and its label property as the label by default. To read them from different properties, set rowValue, rowLabel, colValue, and colLabel accordingly. These props also accept a function that receives the row or column object and returns the resolved value or label.
<VfMatrix
name="schedule"
:cols="[
{ id: 'fri', day: 'Friday' },
{ id: 'sat', day: 'Saturday' },
{ id: 'sun', day: 'Sunday' },
]"
col-value="id"
col-label="day"
:rows="[
{ code: 'am', slot: 'Morning' },
{ code: 'pm', slot: 'Afternoon' },
{ code: 'ev', slot: 'Evening' },
]"
row-value="code"
row-label="slot"
/><template>
<VfMatrix
name="schedule"
:cols="[
{ id: 'fri', day: 'Friday' },
{ id: 'sat', day: 'Saturday' },
{ id: 'sun', day: 'Sunday' },
]"
col-value="id"
col-label="day"
:rows="[
{ code: 'am', slot: 'Morning' },
{ code: 'pm', slot: 'Afternoon' },
{ code: 'ev', slot: 'Evening' },
]"
row-value="code"
row-label="slot"
mode="multiple"
/>
</template><script setup lang="ts">
import { defineSchema, useForm } from '@vueform/ui'
const schema = defineSchema({
schedule: {
type: 'matrix',
cols: [
{ id: 'fri', day: 'Friday' },
{ id: 'sat', day: 'Saturday' },
{ id: 'sun', day: 'Sunday' },
],
colValue: 'id',
colLabel: 'day',
rows: [
{ code: 'am', slot: 'Morning' },
{ code: 'pm', slot: 'Afternoon' },
{ code: 'ev', slot: 'Evening' },
],
rowValue: 'code',
rowLabel: 'slot',
mode: 'multiple',
},
})
const [Form] = useForm({ schema })
</script>
<template>
<Form />
</template>Object Value
In 'single' and 'multiple' modes, setting colValue to null makes the selected values the full column objects instead of a single property.
<VfMatrix name="schedule" :col-value="null" :cols="[
{ id: 'fri', day: 'Friday' },
{ id: 'sat', day: 'Saturday' },
{ id: 'sun', day: 'Sunday' },
]" /><script setup lang="ts">
import { ref } from 'vue'
const mode = ref('single')
</script>
<template>
<VfSelect
v-model="mode"
name="mode"
:items="{ single: 'Single', multiple: 'Multiple' }"
default="multiple"
addon-before="Mode:"
stacked
/>
<VfMatrix
name="schedule"
:cols="[
{ id: 'fri', day: 'Friday' },
{ id: 'sat', day: 'Saturday' },
{ id: 'sun', day: 'Sunday' },
]"
:col-value="null"
col-label="day"
:rows="['Morning', 'Afternoon', 'Evening']"
:mode="mode"
/>
</template><script setup lang="ts">
import { defineSchema, useForm } from '@vueform/ui'
import { ref, computed } from 'vue'
const mode = ref('single')
const schema = comnputed(() => defineSchema({
mode: {
type: 'select',
items: { single: 'Single', multiple: 'Multiple' },
addonBefore: 'Mode:',
default: 'multiple',
stacked: true,
},
schedule: {
type: 'matrix',
cols: [
{ id: 'fri', day: 'Friday' },
{ id: 'sat', day: 'Saturday' },
{ id: 'sun', day: 'Sunday' },
],
colValue: null,
colLabel: 'day',
rows: ['Morning', 'Afternoon', 'Evening'],
mode: mode.value,
},
}))
const [Form] = useForm({ schema })
</script>
<template>
<Form />
</template>Async Function
The rows and cols props can be an async function that returns the items. The function receives the component context as its argument.
<VfMatrix
name="skills"
:cols="async () => {
const { data } = await $http.get('/data/users.json')
return data
}"
:rows="async () => {
const { data } = await $http.get('/data/skills.json')
return data
}"
/><script setup lang="ts">
import { useHttp } from '@vueform/ui'
const $http = useHttp()
</script>
<template>
<VfMatrix
name="skills"
:cols="async () => {
const { data } = await $http.get('/data/users.json')
return data
}"
:rows="async () => {
const { data } = await $http.get('/data/skills.json')
return data
}"
mode="single"
/>
</template><script setup lang="ts">
import { defineSchema, useForm, useHttp } from '@vueform/ui'
const $http = useHttp()
const schema = defineSchema({
skills: {
type: 'matrix',
cols: async () => {
const { data } = await $http.get('/data/users.json')
return data
},
rows: async () => {
const { data } = await $http.get('/data/skills.json')
return data
},
mode: 'single',
},
})
const [Form] = useForm({ schema })
</script>
<template>
<Form />
</template>Retriggering
Use colsTrigger and rowsTrigger to re-resolve the async functions when specific element values change. They accept an array of element paths to watch. The colsDebounce and rowsDebounce props add a delay (in ms) before re-fetching.
<VfSelect
name="department"
:items="['Engineering', 'Design', 'Marketing']"
/>
<VfMatrix
name="skills"
:cols="async () => {
const { data } = await $http.get('/data/skills.json')
return data
}"
:rows=" async ({ form$ }) => {
const { data } = await $http.get(
`/data/users-${form$.model.department}.json`
)
return data
}"
:rows-trigger="['department']"
:rows-debounce="300"
/><script setup lang="ts">
import { useHttp } from '@vueform/ui'
const $http = useHttp()
</script>
<template>
<VfSelect
name="department"
label="Department"
:items="['Engineering', 'Design', 'Marketing']"
default="Engineering"
/>
<VfMatrix
name="skills"
:cols="async () => {
const { data } = await $http.get('/data/skills.json')
return data
}"
:rows=" async ({ form$ }) => {
const { data } = await $http.get(
`/data/users-${form$.model.department}.json`
)
return data
}"
:rows-trigger="['department']"
:rows-debounce="300"
mode="multiple"
/>
</template><script setup lang="ts">
import { defineSchema, useForm, useHttp } from '@vueform/ui'
const $http = useHttp()
const schema = defineSchema({
department: {
type: 'select',
label: 'Department',
items: ['Engineering', 'Design', 'Marketing'],
default: 'Engineering',
},
skills: {
type: 'matrix',
cols: async () => {
const { data } = await $http.get('/data/skills.json')
return data
},
rows: async ({ form$ }) => {
const { data } = await $http.get(`/data/users-${form$.model.department}.json`)
return data
},
rowsTrigger: ['department'],
rowsDebounce: 300,
mode: 'multiple',
},
})
const [Form] = useForm({ schema })
</script>
<template>
<Form />
</template>Endpoints
The rows and cols props also accept an endpoint URL string. Expressions within the string are resolved reactively — when a referenced value changes, the endpoint is re-fetched automatically.
<VfSelect
name="department"
:items="['Engineering', 'Design', 'Marketing']"
/>
<VfMatrix
name="skills"
cols="/data/skills.json"
rows="/data/users-{department}.json"
/><template>
<VfSelect
name="department"
label="Department"
:items="['Engineering', 'Design', 'Marketing']"
default="Engineering"
/>
<VfMatrix
name="skills"
cols="/data/skills.json"
rows="/data/users-{department}.json"
mode="multiple"
/>
</template><script setup lang="ts">
import { defineSchema, useForm } from '@vueform/ui'
const schema = defineSchema({
department: {
type: 'select',
label: 'Department',
items: ['Engineering', 'Design', 'Marketing'],
default: 'Engineering',
},
skills: {
type: 'matrix',
cols: '/data/skills.json',
rows: '/data/users-{department}.json',
mode: 'multiple',
},
})
const [Form] = useForm({ schema })
</script>
<template>
<Form />
</template>endpoint Prop
Alternatively, use the endpoint prop to load both cols and rows from a single request. The response is expected to contain cols and rows keys by default — use colsKey and rowsKey to customize. The method and headers props apply to all endpoint requests.
<VfMatrix
name="skills"
endpoint="/data/matrix.json"
cols-key="skills"
rows-key="users"
method="GET"
:headers="{ 'X-Custom': 'value' }"
/><template>
<VfMatrix
name="skills"
endpoint="/data/matrix.json"
cols-key="skills"
rows-key="users"
method="GET"
:headers="{ 'X-Custom': 'value' }"
mode="multiple"
/>
</template><script setup lang="ts">
import { defineSchema, useForm } from '@vueform/ui'
const schema = defineSchema({
skills: {
type: 'matrix',
endpoint: '/data/matrix.json',
colsKey: 'skills',
rowsKey: 'users',
method: 'GET',
headers: { 'X-Custom': 'value' },
mode: 'multiple',
},
})
const [Form] = useForm({ schema })
</script>
<template>
<Form />
</template>Transformers
The transformEndpoint function reshapes the endpoint response before cols and rows are extracted. Similarly, transformCols and transformRows can transform data from their respective endpoint string sources.
<VfMatrix
name="skills"
endpoint="/data/matrix-data.json"
:transform-endpoint="(data) => ({
cols: data?.data?.skills?.map((c: any) => ({ value: c.id, label: c.title })) || [],
rows: data?.data?.team?.map((u: any) => ({ value: u.id, label: u.name })) || [],
})"
/><template>
<VfMatrix
name="skills"
endpoint="/data/matrix-data.json"
:transform-endpoint="(data) => ({
cols: data?.data?.skills?.map((c: any) => ({ value: c.id, label: c.title })) || [],
rows: data?.data?.team?.map((u: any) => ({ value: u.id, label: u.name })) || [],
})"
mode="multiple"
/>
</template><script setup lang="ts">
import { defineSchema, useForm } from '@vueform/ui'
const schema = defineSchema({
skills: {
type: 'matrix',
endpoint: '/data/matrix-data.json',
transformEndpoint: (data) => ({
cols: data?.data?.skills?.map((c: any) => ({ value: c.id, label: c.title })) || [],
rows: data?.data?.team?.map((u: any) => ({ value: u.id, label: u.name })) || [],
}),
mode: 'multiple',
},
})
const [Form] = useForm({ schema })
</script>
<template>
<Form />
</template>Custom Columns
In 'auto' mode, columns can override the default text input by providing a schema property with an element definition.
<VfMatrix name="inventory" :cols="[
{ value: 'sku', label: 'SKU' },
{ value: 'qty', label: 'Qty' },
{
value: 'status',
label: 'Status',
schema: {
type: 'select',
items: ['In Stock', 'Low', 'Out of Stock'],
placeholder: 'Select',
},
},
]" /><template>
<VfMatrix
name="inventory"
:rows="['Widget', 'Gadgets']"
:cols="[
{ value: 'sku', label: 'SKU' },
{ value: 'qty', label: 'Qty' },
{
value: 'status',
label: 'Status',
schema: {
type: 'select',
items: ['In Stock', 'Low', 'Out of Stock'],
placeholder: 'Select',
},
},
]"
/>
</template><script setup lang="ts">
import { defineSchema, useForm } from '@vueform/ui'
const schema = defineSchema({
inventory: {
type: 'matrix',
rows: ['Widget', 'Gadgets'],
cols: [
{ value: 'sku', label: 'SKU' },
{ value: 'qty', label: 'Qty' },
{
value: 'status',
label: 'Status',
schema: {
type: 'select',
items: ['In Stock', 'Low', 'Out of Stock'],
placeholder: 'Select',
},
},
],
},
})
const [Form] = useForm({ schema })
</script>
<template>
<Form />
</template>Conditions
When rows and cols are arrays of objects, each item can define a conditions property. The row or column is only displayed when its conditions are met.
<VfMatrix
name="notifications"
:cols="[
{ value: 'email', label: 'Email' },
{ value: 'sms', label: 'SMS' },
{ value: 'push', label: 'Push', conditions: [['premium', '==', true]] },
]"
:rows="[
{ value: 'news', label: 'News' },
{ value: 'updates', label: 'Updates' },
{ value: 'offers', label: 'Offers', conditions: [['premium', '==', true]] },
]"
/><template>
<VfCheckbox name="premium" text="Premium plan" />
<VfMatrix
name="notifications"
:cols="[
{ value: 'email', label: 'Email' },
{ value: 'sms', label: 'SMS' },
{ value: 'push', label: 'Push', conditions: [['premium', '==', true]] },
]"
:rows="[
{ value: 'news', label: 'News' },
{ value: 'updates', label: 'Updates' },
{ value: 'offers', label: 'Offers', conditions: [['premium', '==', true]] },
]"
mode="multiple"
/>
</template><script setup lang="ts">
import { defineSchema, useForm } from '@vueform/ui'
const schema = defineSchema({
premium: {
type: 'checkbox',
text: 'Premium plan',
},
notifications: {
type: 'matrix',
cols: [
{ value: 'email', label: 'Email' },
{ value: 'sms', label: 'SMS' },
{ value: 'push', label: 'Push', conditions: [['premium', '==', true]] },
],
rows: [
{ value: 'news', label: 'News' },
{ value: 'updates', label: 'Updates' },
{ value: 'offers', label: 'Offers', conditions: [['premium', '==', true]] },
],
mode: 'multiple',
},
})
const [Form] = useForm({ schema })
</script>
<template>
<Form />
</template>Dynamic Rows
When rows is a number (or omitted), the matrix becomes dynamic — users can add and remove rows. The add and remove buttons are shown automatically.
<VfMatrix name="items" :cols="['Item', 'Qty', 'Price']" :rows="2" /><template>
<VfMatrix name="items" :cols="['Item', 'Qty', 'Price']" :rows="2" />
</template><script setup lang="ts">
import { defineSchema, useForm } from '@vueform/ui'
const schema = defineSchema({
items: {
type: 'matrix',
cols: ['Item', 'Qty', 'Price'],
rows: 2,
},
})
const [Form] = useForm({ schema })
</script>
<template>
<Form />
</template>Row Limits
The min and max props constrain how many rows a dynamic matrix can have. The add button hides when max is reached; the remove button hides when min is reached.
<VfMatrix name="tasks" :rows="2" :min="1" :max="3"/><template>
<VfMatrix
name="tasks"
:rows="2"
:min="1"
:max="3"
:cols="['Task', 'Priority']"
/>
</template><script setup lang="ts">
import { defineSchema, useForm } from '@vueform/ui'
const schema = defineSchema({
tasks: {
type: 'matrix',
rows: 2,
min: 1,
max: 3,
cols: ['Task', 'Priority'],
},
})
const [Form] = useForm({ schema })
</script>
<template>
<Form />
</template>Sorting
The sort prop enables drag-and-drop row reordering on dynamic matrices.
<VfMatrix name="priorities" :rows="3" sort /><template>
<VfMatrix
name="priorities"
:rows="3"
sort
:cols="['Taks', 'Status']"
/>
</template><script setup lang="ts">
import { defineSchema, useForm } from '@vueform/ui'
const schema = defineSchema({
priorities: {
type: 'matrix',
rows: 3,
sort: true,
cols: ['Taks', 'Status'],
},
})
const [Form] = useForm({ schema })
</script>
<template>
<Form />
</template>Tabular
The tabular prop renders the matrix as a bordered table with distinct header backgrounds and rounded corners.
<VfMatrix name="availability" tabular /><template>
<VfMatrix
name="availability"
tabular
mode="multiple"
:cols="{
morning: 'Morning',
afternoon: 'Afternoon',
evening: 'Evening',
}"
:rows="{
mon: 'Monday',
tue: 'Tuesday',
wed: 'Wednesday',
thu: 'Thursday',
fri: 'Friday',
}"
/>
</template><script setup lang="ts">
import { defineSchema, useForm } from '@vueform/ui'
const schema = defineSchema({
availability: {
type: 'matrix',
tabular: true,
mode: 'multiple',
cols: {
morning: 'Morning',
afternoon: 'Afternoon',
evening: 'Evening',
},
rows: {
mon: 'Monday',
tue: 'Tuesday',
wed: 'Wednesday',
thu: 'Thursday',
fri: 'Friday',
},
},
})
const [Form] = useForm({ schema })
</script>
<template>
<Form />
</template>Scrollable
The scrollable prop enables horizontal scrolling when the matrix overflows. Use stickyCols to pin row headers and stickyRows to pin column headers while scrolling.
<VfMatrix name="quarterly" scrollable sticky-cols sticky-rows /><template>
<VfMatrix
name="quarterly"
scrollable
sticky-rows
:cols="{
q1: 'Q1',
q2: 'Q2',
q3: 'Q3',
q4: 'Q4',
q5: 'Q5',
q6: 'Q6',
q7: 'Q7',
q8: 'Q8',
}"
:rows="{
revenue: 'Revenue',
costs: 'Costs',
profit: 'Profit',
}"
/>
</template><script setup lang="ts">
import { defineSchema, useForm } from '@vueform/ui'
const schema = defineSchema({
quarterly: {
type: 'matrix',
scrollable: true,
stickyRows: true,
cols: {
q1: 'Q1',
q2: 'Q2',
q3: 'Q3',
q4: 'Q4',
q5: 'Q5',
q6: 'Q6',
q7: 'Q7',
q8: 'Q8',
},
rows: {
revenue: 'Revenue',
costs: 'Costs',
profit: 'Profit',
},
},
})
const [Form] = useForm({ schema })
</script>
<template>
<Form />
</template>Custom Labels
The addLabel and removeLabel props customize the text of the add and remove buttons in dynamic matrices. You can also use addIcon and removeIcon to change their icons.
<VfMatrix name="contacts" add-label="New contact" remove-label="Remove" /><template>
<VfMatrix
name="contacts"
:rows="1"
add-label="New contact"
remove-label="Remove"
:cols="{ name: 'Name', email: 'Email', phone: 'Phone' }"
/>
</template><script setup lang="ts">
import { defineSchema, useForm } from '@vueform/ui'
const schema = defineSchema({
contacts: {
type: 'matrix',
rows: 1,
addLabel: 'New contact',
removeLabel: 'Remove',
cols: { name: 'Name', email: 'Email', phone: 'Phone' },
},
})
const [Form] = useForm({ schema })
</script>
<template>
<Form />
</template>Column Widths
The minWidth and maxWidth props set the default minimum and maximum width for all columns. When cols is an array of objects, individual columns can override these using minWidth and maxWidth properties — the colMinWidth and colMaxWidth props let you customize which property names to read.
<VfMatrix
name="inventory"
min-width="60px"
max-width="200px"
:cols="[
{ value: 'sku', label: 'SKU', },
{
value: 'name',
label: 'Product Name',
minWidth: '200px',
maxWidth: '1fr',
},
{ value: 'qty', label: 'Qty', },
]"
/><template>
<VfMatrix
name="inventory"
min-width="60px"
max-width="200px"
:cols="[
{ value: 'sku', label: 'SKU', },
{
value: 'name',
label: 'Product Name',
minWidth: '200px',
maxWidth: '1fr',
},
{ value: 'qty', label: 'Qty', },
]"
/>
</template><script setup lang="ts">
import { defineSchema, useForm } from '@vueform/ui'
const schema = defineSchema({
inventory: {
type: 'matrix',
minWidth: '60px',
maxWidth: '200px',
cols: [
{ value: 'sku', label: 'SKU', },
{
value: 'name',
label: 'Product Name',
minWidth: '200px',
maxWidth: '1fr',
},
{ value: 'qty', label: 'Qty', },
],
},
})
const [Form] = useForm({ schema })
</script>
<template>
<Form />
</template>Grid Template Columns
The gridTemplateColumns prop gives full control over the CSS grid-template-columns value. It accepts a string or a function that receives the component context and returns the value.
<VfMatrix
name="data"
:cols="['ID', 'Name', 'Email']"
grid-template-columns="48px 1fr 1fr min-content"
/><template>
<VfMatrix
name="data"
:cols="['ID', 'Name', 'Email']"
grid-template-columns="48px 1fr 1fr min-content"
/>
</template><script setup lang="ts">
import { defineSchema, useForm } from '@vueform/ui'
const schema = defineSchema({
data: {
type: 'matrix',
cols: ['ID', 'Name', 'Email'],
gridTemplateColumns: '48px 1fr 1fr min-content',
},
})
const [Form] = useForm({ schema })
</script>
<template>
<Form />
</template>Validation
Setting required rule on the matrix ensures that:
- In
'auto'mode — all columns in every row must have a non-null value. - In
'single'and'multiple'modes — at least one column must be selected per row.
<VfMatrix
name="preferences"
:cols="['Email', 'SMS', 'Push']"
:rows="['News', 'Updates', 'Offers']"
rules="required"
:mode
/><script setup lang="ts">
import { ref } from 'vue'
const mode = ref('single')
</script>
<template>
<VfForm hide-errors>
<VfSelect
v-model="mode"
name="mode"
:items="{ single: 'Single', multiple: 'Multiple', auto: 'Auto' }"
default="single"
addon-before="Mode:"
stacked
/>
<VfMatrix
name="preferences"
:cols="['Email', 'SMS', 'Push']"
:rows="['News', 'Updates', 'Offers']"
:mode="mode"
rules="required"
/>
<VfButton type="submit" text="Submit" action="submit" />
</VfForm>
</template><script setup lang="ts">
import { defineSchema, useForm } from '@vueform/ui'
import { ref, computed } from 'vue'
const mode = ref('single')
const schema = defineSchema({
mode: {
type: 'select',
items: { single: 'Single', multiple: 'Multiple', auto: 'Auto' },
addonBefore: 'Mode:',
default: 'single',
stacked: true,
},
preferences: {
type: 'matrix',
cols: ['Email', 'SMS', 'Push'],
rows: ['News', 'Updates', 'Offers'],
mode: mode.value,
rules: 'required',
},
submit: {
type: 'button',
text: 'Submit',
action: 'submit',
},
})
const [Form] = useForm({ schema })
</script>
<template>
<Form />
</template>Row Rules
To apply additional rules to individual rows, define them via the rules property on each row object (customizable via rowRules). Per-row rules like required, min, max, between, size, gt, lt, gte, and lte control the selection count for that specific row.
<VfMatrix
name="preferences"
:cols="['Email', 'SMS', 'Push']"
row-rules="validate"
:rows="[
{ value: 'news', label: 'News', validate: 'required|min:2' },
{ value: 'updates', label: 'Updates', validate: 'required' },
{ value: 'offers', label: 'Offers' },
]"
mode="multiple"
/><template>
<VfMatrix
name="preferences"
:cols="['Email', 'SMS', 'Push']"
row-rules="validate"
:rows="[
{ value: 'news', label: 'News', validate: 'required|min:2' },
{ value: 'updates', label: 'Updates', validate: 'required' },
{ value: 'offers', label: 'Offers' },
]"
mode="multiple"
/>
<VfButton type="submit" text="Submit" action="submit" />
</template><script setup lang="ts">
import { defineSchema, useForm } from '@vueform/ui'
const schema = defineSchema({
preferences: {
type: 'matrix',
cols: ['Email', 'SMS', 'Push'],
rowRules: 'validate',
rows: [
{ value: 'news', label: 'News', validate: 'required|min:2' },
{ value: 'updates', label: 'Updates', validate: 'required' },
{ value: 'offers', label: 'Offers' },
],
mode: 'multiple',
},
submit: {
type: 'button',
text: 'Submit',
action: 'submit',
},
})
const [Form] = useForm({ schema })
</script>
<template>
<Form />
</template>For any other validation logic, you can create custom rules.
Disabled
The disabled prop prevents all interaction with the matrix. It also accepts Conditions.
<VfMatrix name="locked" disabled /><template>
<VfMatrix
name="locked"
:rows="['Alpha', 'Beta']"
:cols="['Col A', 'Col B']"
disabled
/>
</template><script setup lang="ts">
import { defineSchema, useForm } from '@vueform/ui'
const schema = defineSchema({
locked: {
type: 'matrix',
disabled: true,
rows: ['Alpha', 'Beta'],
cols: ['Col A', 'Col B'],
},
})
const [Form] = useForm({ schema })
</script>
<template>
<Form />
</template>Props
Configure the component's behavior and appearance with these props.
General
| Prop | Default | Description |
|---|---|---|
name | — | Required. The element's unique identifier and path in the current level of form data model. |
type | 'matrix' | The element type identifier. |
id | — | The HTML id attribute for the input element. |
Layout
| Prop | Default | Description |
|---|---|---|
label | — | The label displayed alongside the element. |
hideLabel | false | Whether to visually hide the element's label. |
heading | — | The heading level to render for the container's title. |
page | — | Page configuration for stepped/tabbed forms. Accepts a simple label or a metadata tuple with at least a label property. |
help | — | A help text displayed below the label. |
columns | — | Responsive grid column sizing for the element's layout. |
layout | true | Custom layout template for this element, false to render the element without any layout wrapper, or true (default) for normal layout. |
spaceTop | — | Adds vertical spacing (padding) above the element. The value maps to a spacing token (1-3): 1 = var(--vf-space-1), .... |
spaceBottom | — | Adds vertical spacing (padding) above the element. The value maps to a spacing token (1-3): 1 = var(--vf-space-1), .... |
lineTop | false | Renders a horizontal line (border) above the element. |
lineBottom | false | Renders a horizontal line (border) below the element. |
Input
| Prop | Default | Description |
|---|---|---|
mode | 'auto' | The selection mode for the matrix. |
tabular | false | Whether the matrix uses a tabular visual style with borders and headers. |
sort | false | Whether to enable drag-and-drop sorting of matrix rows. |
scrollable | false | Whether the matrix is horizontally scrollable on overflow. |
stickyCols | false | Whether column headers stick to the top when scrolling. |
stickyRows | false | Whether row headers stick to the left when scrolling. |
wrapColHeaders | false | Whether column header text can wrap. |
wrapRowHeaders | false | Whether row header text can wrap. |
addLabel | — | The label text for the "add row" button. |
removeLabel | — | The label text for the "remove row" button. |
addIcon | '$add' | The icon identifier for the "add row" button. |
removeIcon | '$remove' | The icon identifier for the "remove row" button. |
sortIcon | '$sort' | The icon identifier for the sort handle button. |
colHeaders | true | Whether to display column headers. |
rowHeaders | true | Whether to display row headers. |
minWidth | 'min-content' | The minimum width of each matrix column. |
maxWidth | '1fr' | The maximum width of each matrix column. |
min | -1 | The minimum number of rows allowed. |
max | -1 | The maximum number of rows allowed. |
gridTemplateColumns | — | CSS grid-template-columns value or a function returning it. |
add | true | Whether adding new rows is enabled. When false, the add button is not rendered. |
remove | true | Whether removing rows is enabled. When false, remove buttons are not rendered. |
headers | — | Custom HTTP headers to include when loading cols or rows from an endpoint. |
method | — | The HTTP method to use when loading cols or rows from an endpoint. Defaults to 'GET'. |
cols | — | The column definitions for the matrix grid. Accepts a plain array, a plain object, an array of objects (customizable via colValue, colLabel, and related props), an endpoint URL string (supporting expressions), or a (possibly async) function receiving the component context. |
rows | — | The row definitions or a fixed number of rows for the matrix grid. Accepts a plain array, a plain object, an array of objects (customizable via rowValue, rowLabel, and related props), an endpoint URL string (supporting expressions), or a (possibly async) function receiving the component context. |
colValue | 'value' | The key or function that resolves each column's value (the key used in the matrix data object) when cols is an array of objects. Defaults to 'value'. Set to null to use the full column object as the value. |
colLabel | 'label' | The key or function that resolves each column's header label when cols is an array of objects. Defaults to 'label'. |
colConditions | 'conditions' | The key or function that resolves each column's conditions when cols is an array of objects. Defaults to 'conditions'. |
colSchema | 'schema' | The key or function that resolves each column's custom element schema when cols is an array of objects. Defaults to 'schema'. |
colMinWidth | 'minWidth' | The key or function that resolves each column's minimum width when cols is an array of objects. Defaults to 'minWidth'. |
colMaxWidth | 'maxWidth' | The key or function that resolves each column's maximum width when cols is an array of objects. Defaults to 'maxWidth'. |
rowValue | 'value' | The key or function that resolves each row's value (the key used in the matrix data object) when rows is an array of objects. Defaults to 'value'. |
rowLabel | 'label' | The key or function that resolves each row's header label when rows is an array of objects. Defaults to 'label'. |
rowConditions | 'conditions' | The key or function that resolves each row's conditions when rows is an array of objects. Defaults to 'conditions'. |
rowRules | 'rules' | The key or function that resolves each row's validation rules when rows is an array of objects. Defaults to 'rules'. |
colsTrigger | — | The source that triggers re-resolution of function-based cols. Accepts an array of element paths whose values are watched, a Ref, or a function used as a watch getter. When omitted, function-based cols are only re-resolved when the cols prop reference itself changes. |
colsDebounce | — | The debounce delay in milliseconds applied before re-resolving cols when an expression path or the colsTrigger source changes. Defaults to no debounce (immediate re-resolution). |
transformCols | — | Transforms data received from a cols endpoint or function into the cols format before normalization. |
rowsTrigger | — | The source that triggers re-resolution of function-based rows. Accepts an array of element paths whose values are watched, a Ref, or a function used as a watch getter. When omitted, function-based rows are only re-resolved when the rows prop reference itself changes. |
rowsDebounce | — | The debounce delay in milliseconds applied before re-resolving rows when an expression path or the rowsTrigger source changes. Defaults to no debounce (immediate re-resolution). |
transformRows | — | Transforms data received from a rows endpoint or function into the rows format before normalization. |
endpoint | — | An endpoint URL (supporting expressions) that loads both the column and row definitions from a single request. Each side can still be overridden by defining cols or rows explicitly. |
colsKey | 'cols' | The key or function that resolves the column definitions from the endpoint response. Defaults to 'cols'. |
rowsKey | 'rows' | The key or function that resolves the row definitions from the endpoint response. Defaults to 'rows'. |
transformEndpoint | — | Transforms data received from the endpoint before the column and row definitions are extracted. |
noExpressions | false | Disables expression resolution for this element. Applies to the element itself only (container elements don't cascade it to their children), and a form-level noExpressions cannot be overridden by setting it to false here. |
description | — | A description text displayed below the element. |
sensitive | false | Whether the element holds sensitive data (passwords, payment details, …). Sensitive values are excluded from locally stored drafts. On a container, the whole subtree is excluded. |
disabled | — | Whether the element is disabled. |
Data
| Prop | Default | Description |
|---|---|---|
modelValue | — | The current value of the element (v-model). |
submit | true | Whether the element value is included in form submission data. |
detached | false | Whether the element is detached from the form's element registry and data model (if applicable). |
transformPayload | — | Transforms the element's value when submitting the form. |
Validation
| Prop | Default | Description |
|---|---|---|
rules | — | Validation rules to apply to the element. |
validateOn | — | Controls when validation is triggered (e.g. on change, blur, or submit). |
debounce | — | Delay in milliseconds before processing input. |
bail | true | Whether to stop validation after the first failing rule. |
ruleMessages | — | Custom error messages keyed by validation rule name. |
displayName | — | The display name used in validation error messages. |
maxErrors | 1 | Maximum number of validation errors to display at once. |
hideErrors | false | Whether to hide validation error messages. |
showRequired | — | Where to show required field indicators (e.g. label, placeholder). |
hoist | false | Whether to push the element's errors to its nearest ancestor element. |
Conditions
| Prop | Default | Description |
|---|---|---|
conditions | — | Conditions that control the element's visibility and availability. |
conditionsTrigger | — | The source that triggers re-evaluation of this element's async conditional props (conditions, disabled, readonly, and validation rule conditions). Accepts an array of element paths whose values are watched, a Ref, or a function used as a watch getter. When omitted, any change in the form model re-triggers evaluation. |
conditionsDebounce | — | The debounce delay in milliseconds applied before re-evaluating this element's async conditional props when the trigger source changes. Overrides the global $conditions.debounce config (default 300). |
Customization
| Prop | Default | Description |
|---|---|---|
parts | — | Custom DOM attribute overrides for the component's structural parts. |
class | — | CSS classes to apply to the component's root element. |
classes | — | Custom CSS class overrides for the component's structural parts. |
reclass | — | CSS class overrides that replace (rather than merge with) default classes. |
tokens | — | Token overrides applied to the element's CSS custom properties. |
slots | — | Custom Vue components to use for named slots. Every component resolves it through the standard outlets pipeline (see useOutlets). |
presets | — | Named configuration presets to apply to the component. |
template | — | A custom Vue component to use as the template instead of the default. |
component | — | A custom Vue component to render in the component's default slot. |
Context
Reactive properties and methods accessible on the component's Context object.
General
| Name | Description |
|---|---|
type | The element's type identifier (e.g. "text", "checkbox", "select"). |
name | The element's name as a string ref. |
props | The resolved component props with defaults applied. |
Matrix
| Name | Description |
|---|---|
resolvedRows | The fully resolved matrix rows with component info, props, column mappings, and slot assignments. |
resolvedCols | The fully resolved matrix columns with component info, labels, conditions, and width constraints. |
headers | The column headers array, including optional row header and remove button placeholders. |
showRowHeaders | Whether row headers should be displayed. |
showColHeaders | Whether column headers should be displayed. |
add() | Adds one or more items to a dynamic list. |
remove() | Removes an item from a dynamic list by index. |
sort() | Sorts a dynamic list by moving an item from one data index to another. |
addLabel | The resolved label text for the add row button. |
removeLabel | The resolved label text for the remove row button. |
description | The resolved description text for the element. |
descriptionId | The DOM id for the element's description text region. |
validation | Per-language validation views keyed by language (default for non-translatable elements). |
validator | The validator instance the element is registered with: the form's validator, a store-attached one, or a newly created one. |
shouldValidate | Whether the element should validate live on user input, per the validateOn policy and the form's state. |
onUserInput() | Validates the element on user input when the live-validation policy allows it. |
isFlatContainer | Whether the element's data is flattened into the parent container rather than nested under its own name key. |
containerModel | The model ref the element provides to its children via the container context: the parent's model for flat containers, the element's own model otherwise. |
handleModelUpdate() | Handles a native input event and updates the model from the event target. |
initValidation() | Registers the element with the validator and compiles its rules. |
destroyValidation() | Unregisters the element from the validator and clears its validation views. |
dragIndex | The data index of the item currently being dragged in a sortable list. |
dropIndex | The data index where the dragged item will be dropped. |
rootModel | The root model backing the form when this element operates as the form root, undefined for every other element. |
sensitivePaths | Data paths holding sensitive data (sensitive: true) within this element's subtree — excluded from locally stored drafts. |
list | Ref to the container's root DOM element, used for drag-and-drop bounds detection. |
canSort | Whether the sort handle should be rendered. Returns false when the element is disabled or the optional sortable guard is falsy. |
dropTarget | The stable id rendered at the current drop position (in the live display order), or undefined when not hovering over a valid target. The list template compares this against each row's id to flag the drop target. |
canAdd | Whether the add row button should be displayed, based on dynamic mode, disabled state, and max limit. |
canRemove | Whether the remove row button should be displayed, based on dynamic mode, disabled state, and min limit. |
gridClass | A unique CSS class scoped to this matrix instance, used to target the injected grid style rule. |
gridColumns | The computed grid-template-columns value based on visible columns, row headers, and remove button state. |
addIcon | The resolved icon identifier for the "add" button. |
removeIcon | The resolved icon identifier for the "remove" button. |
sortIcon | The resolved icon identifier for the sort handle button. |
Data
| Name | Description |
|---|---|
model | The element's reactive model value within the form data tree. |
value | The current language-aware value of the element. For translatable elements, returns the value for the active language. |
payload | The element's submission payload. Container elements aggregate from children; leaf elements return their own value. |
nullValue | The value the element holds when it is considered empty. For translatable elements a per-language object is returned. |
initialModel | A snapshot of the model at initialization time, used for dirty checking and reset. |
dataPath | The dot-notation path to this element's value within the form data object (e.g. "address.city"). Empty string for the root model. Flat containers inherit their parent's data path. |
tracking | Whether the element's default expression is currently tracked and auto-updating the value. |
update() | Updates the element's model value. Container elements perform a deep merge; leaf elements set the value directly. |
load() | Loads data into the element and fires the load event, cascading to all children. |
reset() | Resets the element to its initial model state and fires the reset event. |
clear() | Clears the element to its null value and fires the clear event. |
track() | Resumes expression tracking after an untrack, immediately re-writing the resolved value. |
untrack() | Stops expression tracking, leaving the current value in place. |
reinit() | Reinitializes the element by rebuilding both its model registration and validation instances. |
State
| Name | Description |
|---|---|
visible | Whether the element is currently visible, based on availability, container visibility, and pager state. |
available | Whether the element is available (not hidden by conditional logic). |
disabled | Whether the element is currently disabled, considering form state, parent container state, local override, and the disabled prop. The prop is evaluated through the conditions pipeline, so sync and async conditional values are supported uniformly. |
dirty | Whether the current model value differs from the initial model value. |
empty | Whether the element's current value is empty. Container elements check whether all children are empty. |
busy | Whether the element is busy, meaning it is either debouncing or has pending async validation. |
hoisted | Whether this element pushes its errors to its nearest ancestor element instead of displaying and reporting them itself. |
enable() | Programmatically enables the element. |
disable() | Programmatically disables the element. |
Validation
| Name | Description |
|---|---|
invalid | Whether any of the element's validations (across all languages) are currently invalid, including children. |
validated | Whether all of the element's validations (across all languages) have been executed, including children. |
completed | Whether the element is completed, meaning it either has no rules or has been validated without errors. |
success | Whether the element has been validated and passed (always true for elements without own rules), once touched. |
pending | Whether any of the element's validations are currently pending an async check, including children. |
debouncing | Whether any of the element's validations are currently debouncing, including children. |
errors | All error messages for this element: its own plus any pushed up by hoisted children. |
hasError | Whether the element has any active error messages. |
displayErrors | The error messages rendered for this element. Empty when the element pushes its errors to its parent; otherwise errors capped by maxErrors. |
ownErrors | The element's own error messages (validation rules plus custom message bag entries). |
formErrors | Error messages propagated to the form, keyed by element path. Empty when the element pushes its errors to its parent. |
messages | The list of custom messages from the message bag, including messages from hoisted children. |
messageBag | The element's message bag for custom errors and messages. |
required | Whether the element is required by its current validation rules. |
genericName | A human-readable name resolved from displayName, label, floating, placeholder, or the element's name prop. |
validate() | Runs validation on the element's own rules and all children, returning whether everything is valid. |
validateSelf() | Validates the element's own rules (without children), resolving with the result. |
validateChildren() | Validates stateful children, returning whether all are valid. By default only incomplete children run. |
invalidate() | Marks all validation instances as invalidated, requiring revalidation. |
unvalidate() | Resets all validation state, including children's. |
filled() | Checks whether a value is considered filled. |
clean() | Marks the element as clean by updating the initial model snapshot. |
clearErrors() | Clears all error messages from the message bag. |
clearMessages() | Clears all custom messages from the message bag. |
clearMessageBag() | Clears the entire message bag, removing both errors and messages. |
Layout
| Name | Description |
|---|---|
id | The resolved element id, using the id prop or falling back to the auto-generated uid. |
label | The resolved label text for the element. |
help | The resolved help text for the element. |
page | Page metadata for stepped/tabbed forms. |
classes | The resolved CSS class map for the component. |
parts | The resolved DOM attribute overrides for internal elements. |
nonce | Unique security nonce for injecting scoped styles. |
viewLoaded | Whether the element's view has been loaded (used for lazy rendering optimization). |
$el | Reference to the component's root DOM element. |
resolvedColumns | Resolved column sizes per breakpoint, normalized into container/label/wrapper/group values. |
updateColumns() | Updates the column configuration programmatically. |
scrollTo() | Scrolls the window to this element. If the element belongs to a step or tab, that page is selected first before scrolling. |
focus() | Focuses the first focusable HTML element (input, select, textarea, button, etc.) within the wrapper. Optionally scrolls to the element first. |
Tree
| Name | Description |
|---|---|
form$ | The parent form's context, providing access to form-level state and methods. |
path | The element's dot-notation path in the form tree (e.g. "user.name"). |
componentName | The resolved Vue component name for this element. |
container | The container context providing path, model, and registration methods for child elements. |
children | The child element registry providing registration, unregistration, and reactive child lists. |
Events
| Name | Description |
|---|---|
fire() | Fires an event synchronously, invoking before, main, and after listeners in order. |
fireAsync() | Fires an event asynchronously, awaiting each callback and short-circuiting when any returns false. |
on() | Subscribes a callback to a specific event. |
off() | Removes a previously registered event callback. |
onBefore() | Registers a callback that runs before the main event listeners. |
onAfter() | Registers a callback that runs after the main event listeners. |
Handlers
| Name | Description |
|---|---|
handleAdd() | Event handler that adds a new row to the matrix. |
handleRemove() | Event handler that removes a row at the given index from the matrix. |
handleDragStart() | Initiates drag-and-drop reordering for the item at the given data index. |
handleDragEnter() | Updates the current drop target during drag-and-drop. index is the hovered row's live display position; the dragged item moves straight to it (its origin position included, so it can be dropped back home). dragIndex stays the canonical data index that feeds move/sort as the source. |
handleDrop() | Completes the drag-and-drop operation by sorting the dragged item to the drop position. |
handleDragEnd() | Cleans up drag-and-drop state after the operation ends. |
handleWrapperDragOver() | Prevents default dragover behavior on the container to allow drops. |
Accessibility
| Name | Description |
|---|---|
uid | A unique auto-generated identifier for the element. |
helpId | The DOM id for the element's help text region. |
errorId | The DOM id for the element's error message region. |
labelId | The DOM id for the element's label region. |
Events
Events emitted by the component. See Events for details.
| Name | Params | Description |
|---|---|---|
change | newValue, oldValue, context$ | Emitted when the element value changes. |
update:modelValue | value | Emitted to update the v-model binding. |
load | value, context$ | Emitted when the element's value is loaded programmatically via the load method. |
reset | context$ | Emitted when the element is reset to its default value. |
clear | context$ | Emitted when the element's value is cleared. |
invalid | context$ | Emitted when the element becomes invalid. |
valid | context$ | Emitted when the element becomes valid after having been invalid. |
beforeMount | context$ | Emitted before the component is mounted. |
mounted | context$ | Emitted after the component is mounted. |
beforeUnmount | context$ | Emitted before the component is unmounted. |
unmounted | context$ | Emitted after the component is unmounted. |
updated | context$ | Emitted after the component is updated. |
Slots
Named Slots for replacing parts of the component's rendering.
| Name | Scope | Description |
|---|---|---|
template | context | Slot that replaces the entire component rendering. Receives the full component context as a single context prop. |
label | label | Slot for customizing the element's label content. |
required | — | Slot for customizing the required indicator. |
help | help | Slot for customizing the help text. |
default | — | Slot for the default matrix content. |
header | headers bindings | Slot that replaces the header row. Receives the header part's resolved bindings and the header definitions. |
col-header | id label bindings | Slot that replaces each column header cell. |
row | index rowHeader beingDragged isDropTarget canRemove canSort label cols handleDragEnter handleDragStart handleDragEnd remove | Slot that replaces each matrix row. Receives row state, drag handlers, label, remove handler, and columns. |
row-header | label bindings | Slot that replaces each row header cell. |
sort-wrapper | bindings handleDragEnter handleDragStart handleDragEnd | Slot that replaces the drag sort handle wrapper. |
sort | bindings handleDragEnter handleDragStart handleDragEnd | Slot that replaces the drag handle. Receives the handle's bindings and drag event handlers. |
cell | component props bindings handleDragEnter | Slot that replaces each matrix cell. Receives the component, props for the cell element, and a drag enter handler for sortable rows. |
remove-wrapper | bindings handleRemove | Slot that replaces the row remove button wrapper. |
remove | bindings handleRemove | Slot that replaces the row remove button. |
add | label bindings handleAdd | Slot that replaces the add row button. Receives the button's bindings, label, and add handler. |
description | description | Slot for customizing the description text. |
errors | errors | Slot for customizing the validation errors display. |
messages | messages | Slot for customizing the info messages display. |
Parts
DOM attribute overrides targeting internal elements. See Parts for details.
panel
The wrapper around root with display: contents when the element is a step or a tab.
| Element | <div> |
| Classes | .vf-panel |
root
The element's root wrapper.
| Element | <div> <fieldset> |
| Classes | .vf-element .vf-space-top-1? .vf-space-top-2? .vf-space-top-3? .vf-space-bottom-1? .vf-space-bottom-2? .vf-space-bottom-3? .vf-line-top? .vf-line-bottom? .vf-matrix .vf-tabular? .vf-wrap-col-headers? .vf-wrap-row-headers? |
| Bindings | data-align-label |
labelGroup
The container holding the label and required indicator.
| Element | <div> |
| Classes | .vf-label-group |
label
The label element; renders as the corresponding heading when the container's heading prop is set.
| Element | <span> <h1> <h2> <h3> <h4> <h5> <h6> |
| Classes | .vf-label |
required
The required indicator.
| Element | <div> |
| Classes | .vf-required |
elementGroup
The container wrapping the input and related UI.
| Element | <div> |
| Classes | .vf-element-group |
elementWrapper
The wrapper directly around the input control.
| Element | <div> |
| Classes | .vf-element-wrapper |
help
The help text area.
| Element | <div> |
| Classes | .vf-help |
grid
The grid layout element.
| Element | <div> |
| Classes | .vf-matrix-grid |
| Bindings | data-scrollable |
header
The header row element with display: contents.
| Element | <div> |
| Classes | .vf-matrix-header |
colHeader
Each column header element.
| Element | <div> |
| Classes | .vf-matrix-col-header |
| Bindings | data-sticky |
srOnlyHeader
The screen-reader-only header element.
| Element | <div> |
row
Each row element with display: contents.
| Element | <div> |
| Classes | .vf-matrix-row |
| Bindings | data-dragging data-drop-target |
rowHeader
Each row header element.
| Element | <div> |
| Classes | .vf-matrix-row-header |
| Bindings | data-sticky |
cell
Each cell element.
| Element | <div> |
| Classes | .vf-matrix-cell |
sortWrapper
The drag sort handle wrapper element.
| Element | <div> |
| Classes | .vf-matrix-row-sort |
removeWrapper
The row remove button wrapper element.
| Element | <div> |
| Classes | .vf-matrix-row-remove |
sort
The drag sort handle element.
| Element | <VfButton> |
| Classes | .vf-matrix-sort |
| Bindings | aria-label |
remove
The remove action element.
| Element | <VfButton> |
| Classes | .vf-matrix-remove |
| Bindings | aria-label |
add
The add action element.
| Element | <VfButton> |
| Classes | .vf-matrix-add |
| Bindings | aria-label |
description
The description text area.
| Element | <div> |
| Classes | .vf-description |
errors
The validation errors container.
| Element | <div> |
| Classes | .vf-errors |
error
An individual validation error.
| Element | <div> |
| Classes | .vf-error |
messages
The info messages container.
| Element | <div> |
| Classes | .vf-messages |
message
An individual info message.
| Element | <div> |
| Classes | .vf-message |
Tokens
All the CSS variables that control this component's appearance with default values in the default theme. See Theming Guide for details.
:root {
/**
* Element tokens
* -------------------------------------------------------------------------- */
--vf-matrix-gutter-x: var(--vf-gutter);
--vf-matrix-gutter-y: var(--vf-gutter);
--vf-matrix-col-header-color: inherit;
--vf-matrix-header-font-size: 1rem;
--vf-matrix-header-font-weight: 700;
--vf-matrix-row-header-color: inherit;
--vf-matrix-dragging-opacity: 0.6;
--vf-matrix-add-margin: var(--vf-gutter) 0 0 0;
--vf-tabular-bg: var(--vf-white);
--vf-tabular-border-color: var(--vf-gray-300);
--vf-tabular-border-style: solid;
--vf-tabular-border-width: 1px;
--vf-tabular-radius: var(--vf-radius);
--vf-tabular-cell-min-height: calc(1lh + var(--vf-input-pt) + var(--vf-input-pb) + var(--vf-input-border-width-t) + var(--vf-input-border-width-b));
--vf-tabular-text-cell-padding: var(--vf-py) var(--vf-px);
--vf-tabular-col-header-bg: var(--vf-gray-100);
--vf-tabular-col-header-border-color: var(--vf-gray-300);
--vf-tabular-col-header-color: inherit;
--vf-tabular-header-font-size: 1rem;
--vf-tabular-header-font-weight: 700;
--vf-tabular-header-padding: var(--vf-py) var(--vf-px);
--vf-tabular-row-header-bg: var(--vf-gray-100);
--vf-tabular-row-header-border-color: var(--vf-gray-300);
--vf-tabular-row-header-color: inherit;
--vf-tabular-color: var(--vf-gray-800);
/**
* Shared element layout tokens
* -------------------------------------------------------------------------- */
--vf-element-line-color: var(--vf-gray-300);
--vf-label-font-size: 1rem;
--vf-label-font-weight: 600;
--vf-label-group-h-padding: calc(var(--vf-py) + var(--vf-border-width-t)) 0 0 0;
--vf-label-group-v-padding: 0 0 0.375rem 0;
--vf-required-bg: transparent;
--vf-required-color: inherit;
--vf-required-content: '*';
--vf-required-h: auto;
--vf-required-icon: none;
--vf-required-w: auto;
--vf-help-bg: transparent;
--vf-help-border-color: transparent;
--vf-help-border-style: solid;
--vf-help-border-width: 0;
--vf-help-color: var(--vf-text-soft);
--vf-help-font-size: 0.875rem;
--vf-help-padding: 0;
--vf-help-radius: var(--vf-radius);
--vf-description-bg: transparent;
--vf-description-border-color: transparent;
--vf-description-border-style: solid;
--vf-description-border-width: 0;
--vf-description-color: var(--vf-text-soft);
--vf-description-font-size: 0.875rem;
--vf-description-padding: 0;
--vf-description-radius: var(--vf-radius);
--vf-errors-bg: transparent;
--vf-errors-border-color: transparent;
--vf-errors-border-style: solid;
--vf-errors-border-width: 0;
--vf-errors-color: var(--vf-red);
--vf-errors-font-size: 0.875rem;
--vf-errors-padding: 0;
--vf-errors-radius: var(--vf-radius);
--vf-messages-bg: transparent;
--vf-messages-border-color: var(--vf-border-success);
--vf-messages-border-style: solid;
--vf-messages-border-width: 0;
--vf-messages-color: var(--vf-green);
--vf-messages-font-size: 0.875rem;
--vf-messages-padding: 0;
--vf-messages-radius: var(--vf-radius);
--vf-input-border-width-l: var(--vf-border-width-l);
--vf-icon-font-size: 0.875rem;
--vf-icon-group-color: inherit;
--vf-icon-group-color-danger: var(--vf-color-danger);
--vf-icon-group-width: 2.5rem;
--vf-element-group-gutter-x: 0;
--vf-element-group-gutter-y: 0.25rem;
--vf-element-wrapper-padding: 0;
/**
* Semantic tokens
* -------------------------------------------------------------------------- */
--vf-icon-height: 0.75rem;
--vf-icon-width: 0.75rem;
/**
* Primitives tokens
* -------------------------------------------------------------------------- */
--vf-space-1: 1rem;
--vf-space-2: 2rem;
--vf-space-3: 3rem;
--vf-icon-loading: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='6.5' fill='none' stroke='currentColor' stroke-width='1.5' stroke-dasharray='30.6 10.2' stroke-linecap='round'/%3E%3C/svg%3E");
}{
/**
* Element tokens
* -------------------------------------------------------------------------- */
matrixGutterX: '$gutter',
matrixGutterY: '$gutter',
matrixColHeaderColor: 'inherit',
matrixHeaderFontSize: '1rem',
matrixHeaderFontWeight: '700',
matrixRowHeaderColor: 'inherit',
matrixDraggingOpacity: '0.6',
matrixAddMargin: '$gutter 0 0 0',
tabularBg: '$white',
tabularBorderColor: '$gray300',
tabularBorderStyle: 'solid',
tabularBorderWidth: '1px',
tabularRadius: '$radius',
tabularCellMinHeight: 'calc(1lh + var(--vf-input-pt) + var(--vf-input-pb) + var(--vf-input-border-width-t) + var(--vf-input-border-width-b))',
tabularTextCellPadding: '$py $px',
tabularColHeaderBg: '$gray100',
tabularColHeaderBorderColor: '$gray300',
tabularColHeaderColor: 'inherit',
tabularHeaderFontSize: '1rem',
tabularHeaderFontWeight: '700',
tabularHeaderPadding: '$py $px',
tabularRowHeaderBg: '$gray100',
tabularRowHeaderBorderColor: '$gray300',
tabularRowHeaderColor: 'inherit',
tabularColor: '$gray800',
/**
* Shared element layout tokens
* -------------------------------------------------------------------------- */
elementLineColor: '$gray300',
labelFontSize: '1rem',
labelFontWeight: '600',
labelGroupHPadding: 'calc($py + $borderWidthT) 0 0 0',
labelGroupVPadding: '0 0 0.375rem 0',
requiredBg: 'transparent',
requiredColor: 'inherit',
requiredContent: "'*'",
requiredH: 'auto',
requiredIcon: 'none',
requiredW: 'auto',
helpBg: 'transparent',
helpBorderColor: 'transparent',
helpBorderStyle: 'solid',
helpBorderWidth: '0',
helpColor: '$textSoft',
helpFontSize: '0.875rem',
helpPadding: '0',
helpRadius: '$radius',
descriptionBg: 'transparent',
descriptionBorderColor: 'transparent',
descriptionBorderStyle: 'solid',
descriptionBorderWidth: '0',
descriptionColor: '$textSoft',
descriptionFontSize: '0.875rem',
descriptionPadding: '0',
descriptionRadius: '$radius',
errorsBg: 'transparent',
errorsBorderColor: 'transparent',
errorsBorderStyle: 'solid',
errorsBorderWidth: '0',
errorsColor: '$red',
errorsFontSize: '0.875rem',
errorsPadding: '0',
errorsRadius: '$radius',
messagesBg: 'transparent',
messagesBorderColor: '$borderSuccess',
messagesBorderStyle: 'solid',
messagesBorderWidth: '0',
messagesColor: '$green',
messagesFontSize: '0.875rem',
messagesPadding: '0',
messagesRadius: '$radius',
inputBorderWidthL: '$borderWidthL',
iconFontSize: '0.875rem',
iconGroupColor: 'inherit',
iconGroupColorDanger: '$colorDanger',
iconGroupWidth: '2.5rem',
elementGroupGutterX: '0',
elementGroupGutterY: '0.25rem',
elementWrapperPadding: '0',
/**
* Semantic tokens
* -------------------------------------------------------------------------- */
iconHeight: '0.75rem',
iconWidth: '0.75rem',
/**
* Primitives tokens
* -------------------------------------------------------------------------- */
space1: '1rem',
space2: '2rem',
space3: '3rem',
iconLoading: "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='6.5' fill='none' stroke='currentColor' stroke-width='1.5' stroke-dasharray='30.6 10.2' stroke-linecap='round'/%3E%3C/svg%3E\")",
}