The <VueListAttributes> component provides UI controls for showing/hiding columns in a table or attributes in a list. It’s useful for letting users customize which fields they want to see.
Basic usage
< template >
< VueList endpoint = "users" : attrs = " [ 'name' , 'email' , 'role' , 'created_at' ] " >
< VueListAttributes />
< VueListItems # default = " { items } " >
< div v-for = " user in items " : key = " user . id " >
{{ user . name }} - {{ user . email }}
</ div >
</ VueListItems >
</ VueList >
</ template >
Props
This component has no props. It uses Vue’s inject to access the list state from the parent <VueList> component.
Important : You must pass the attrs prop to the <VueList> component to define which attributes are available.
Slot
The default slot receives a scope object:
< VueListAttributes # default = " { attrs , settings , update } " >
<div class="attribute-controls">
<label v-for="attr in attrs" :key="attr.name">
<input
type="checkbox"
:checked="settings?.[attr.name]?.visible"
@change="update(attr.name, 'visible', $event.target.checked)"
/>
{{ attr.label }}
</label>
</div>
</ VueListAttributes >
Scope object
attrs - Array of attribute objects with name and label
settings - Current settings object (e.g., { name: { visible: true }, email: { visible: false } })
update(name, prop, value) - Function to update an attribute’s settings
Examples
Checkbox list
< VueListAttributes # default = " { attrs , settings , update } " >
<div class="space-y-2">
<p class="text-sm font-medium text-gray-700">Show columns:</p>
<label
v-for="attr in attrs"
:key="attr.name"
class="flex items-center gap-2 cursor-pointer"
>
<input
type="checkbox"
:checked="settings?.[attr.name]?.visible"
@change="update(attr.name, 'visible', $event.target.checked)"
class="rounded"
/>
<span class="text-sm">{{ attr.label }}</span>
</label>
</div>
</ VueListAttributes >
< VueListAttributes # default = " { attrs , settings , update } " >
<div class="relative">
<button @click="showMenu = !showMenu" class="btn-secondary">
Columns
<svg class="w-4 h-4 ml-2" fill="none" stroke="currentColor">
<path d="M19 9l-7 7-7-7" />
</svg>
</button>
<div v-if="showMenu" class="absolute right-0 mt-2 bg-white shadow-lg rounded-lg p-4 z-10">
<label
v-for="attr in attrs"
:key="attr.name"
class="flex items-center gap-2 py-1"
>
<input
type="checkbox"
:checked="settings?.[attr.name]?.visible"
@change="update(attr.name, 'visible', $event.target.checked)"
/>
<span>{{ attr.label }}</span>
</label>
</div>
</div>
</ VueListAttributes >
< script setup >
import { ref } from 'vue'
const showMenu = ref ( false )
</ script >
With select all / deselect all
< VueListAttributes # default = " { attrs , settings , update } " >
<div class="column-selector">
<div class="flex items-center justify-between mb-3">
<p class="font-medium">Columns</p>
<div class="flex gap-2">
<button @click="selectAll(attrs, update)" class="text-xs text-blue-600">
Select All
</button>
<button @click="deselectAll(attrs, update)" class="text-xs text-gray-600">
Clear
</button>
</div>
</div>
<div class="space-y-2">
<label v-for="attr in attrs" :key="attr.name" class="flex items-center gap-2">
<input
type="checkbox"
:checked="settings?.[attr.name]?.visible"
@change="update(attr.name, 'visible', $event.target.checked)"
/>
<span>{{ attr.label }}</span>
</label>
</div>
</div>
</ VueListAttributes >
< script setup >
function selectAll ( attrs , update ) {
attrs . forEach ( attr => update ( attr . name , 'visible' , true ))
}
function deselectAll ( attrs , update ) {
attrs . forEach ( attr => update ( attr . name , 'visible' , false ))
}
</ script >
Using with table
< template >
< VueList endpoint = "users" : attrs = " columns " >
< div class = "mb-4" >
< VueListAttributes # default = " { attrs , settings , update } " >
< div class = "flex gap-2" >
< label v-for = " attr in attrs " : key = " attr . name " class = "inline-flex items-center gap-1" >
< input
type = "checkbox"
: checked = " settings ?.[ attr . name ]?. visible "
@ change = " update ( attr . name , 'visible' , $event . target . checked ) "
/>
< span class = "text-sm" > {{ attr . label }} </ span >
</ label >
</ div >
</ VueListAttributes >
</ div >
< table class = "w-full" >
< thead >
< tr >
< th v-if = " isVisible ( 'name' ) " > Name </ th >
< th v-if = " isVisible ( 'email' ) " > Email </ th >
< th v-if = " isVisible ( 'role' ) " > Role </ th >
< th v-if = " isVisible ( 'created_at' ) " > Created </ th >
</ tr >
</ thead >
< tbody >
< VueListItems # default = " { items } " >
< tr v-for = " user in items " : key = " user . id " >
< td v-if = " isVisible ( 'name' ) " > {{ user . name }} </ td >
< td v-if = " isVisible ( 'email' ) " > {{ user . email }} </ td >
< td v-if = " isVisible ( 'role' ) " > {{ user . role }} </ td >
< td v-if = " isVisible ( 'created_at' ) " > {{ user . created_at }} </ td >
</ tr >
</ VueListItems >
</ tbody >
</ table >
</ VueList >
</ template >
< script setup >
import { inject } from 'vue'
const columns = [
{ name: 'name' , label: 'Name' },
{ name: 'email' , label: 'Email' },
{ name: 'role' , label: 'Role' },
{ name: 'created_at' , label: 'Created At' }
]
const attrSettings = inject ( 'attrSettings' )
function isVisible ( attrName ) {
return attrSettings . value ?.[ attrName ]?. visible !== false
}
</ script >
Popover style
< VueListAttributes # default = " { attrs , settings , update } " >
<div class="relative">
<button
@click="showPopover = !showPopover"
class="flex items-center gap-2 px-3 py-2 border rounded hover:bg-gray-50"
>
<svg class="w-4 h-4" fill="none" stroke="currentColor">
<path d="M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4" />
</svg>
<span class="text-sm">Customize Columns</span>
</button>
<div
v-if="showPopover"
class="absolute right-0 mt-2 w-64 bg-white border rounded-lg shadow-xl p-4 z-20"
>
<h3 class="font-medium mb-3">Show/Hide Columns</h3>
<div class="space-y-2 max-h-64 overflow-y-auto">
<label
v-for="attr in attrs"
:key="attr.name"
class="flex items-center gap-2 p-2 hover:bg-gray-50 rounded cursor-pointer"
>
<input
type="checkbox"
:checked="settings?.[attr.name]?.visible"
@change="update(attr.name, 'visible', $event.target.checked)"
class="rounded"
/>
<span class="text-sm">{{ attr.label }}</span>
</label>
</div>
</div>
</div>
</ VueListAttributes >
< script setup >
import { ref } from 'vue'
const showPopover = ref ( false )
</ script >
Accessing visibility state
You can check if an attribute is visible using the injected attrSettings:
< script setup >
import { inject , computed } from 'vue'
const attrSettings = inject ( 'attrSettings' )
const isNameVisible = computed (() => {
return attrSettings . value ?. name ?. visible !== false
})
</ script >
State persistence
Attribute visibility is automatically persisted via the stateManager if configured. When users return, their column preferences are restored.
app . use ( VueList , {
requestHandler ( context ) {
// ... your request handler
},
stateManager: {
init ( context ) {
// Initialize state
},
get ( context ) {
const key = `vuelist- ${ context . endpoint } - ${ context . version } `
const state = localStorage . getItem ( key )
return state ? JSON . parse ( state ) : null
},
set ( context ) {
const key = `vuelist- ${ context . endpoint } - ${ context . version } `
const state = {
attrSettings: context . attrSettings , // Column visibility saved here
page: context . page ,
perPage: context . perPage
}
localStorage . setItem ( key , JSON . stringify ( state ))
}
}
})
Use attribute visibility in combination with responsive design to hide less important columns on mobile devices by default.
The attrs prop on <VueList> can be an array of strings or objects with name and label properties.
Next steps
VueList props Learn about the attrs prop
State persistence Save attribute preferences