List View
Create your own custom list while using the block's features.
Usage
MeListView does not provide a default view of your data. Use the cell scoped slot ({ cell, column, getValue, renderValue, row, table }) to compose each row. To enable sticky header and footer behavior, the block must have an explicit height set. See Table for more information.
<template>
<MeListView
v-model:row-selection="rowSelection"
v-model:active-row="activeRow"
v-model:pagination="pagination"
:data="data"
active-behavior
selectable
>
<template #header>
Header action
</template>
<template #cell="{ row }">
<MeForehead
:text-banner="{ label: row.original.label, code: row.original.code }"
banner-variant="text"
>
<template #leading>
<div class="flex flex-col gap-y-[6px]">
<span class="text-base text-default font-semibold">
{{ row.original.code }} - {{ row.original.name }}
</span>
<span class="text-xs text-muted font-normal">
{{ row.original.description }}
</span>
</div>
</template>
<template #trailing>
<div class="flex flex-col justify-between items-end h-full">
<span class="text-base text-default font-semibold">
{{ row.original.price }}
</span>
<MeForeheadActionBar
:actions="[
{ icon: 'i-lucide-heart' },
{ icon: 'i-lucide-wand-sparkles' }
]"
:dropdown-items="[
{ label: 'Duplicate', icon: 'i-lucide-copy', onSelect: () => {} },
{ label: 'Delete', icon: 'i-lucide-trash', onSelect: () => {} }
]"
see-more
/>
</div>
</template>
</MeForehead>
</template>
<template #footer>
Footer action
</template>
</MeListView>
</template>
<script setup>
const rowSelection = ref({ item2: true })
const pagination = ref({ pageIndex: 0, pageSize: 2 })
const activeRow = ref(undefined)
const data = [
{
id: 'item1',
label: 'Item 1',
code: '123',
name: 'Requisição',
price: 'BRL 100,00',
description: 'Descrição 1'
},
{
id: 'item2',
label: 'Item 2',
code: '456',
name: 'Cotação',
price: 'BRL 200,00',
description: 'Descrição 2'
},
{
id: 'item3',
label: 'Item 3',
code: '789',
name: 'Pedido',
price: 'BRL 300,00',
description: 'Descrição 3'
},
{
id: 'item4',
label: 'Item 4',
code: '101',
name: 'Mercado Eletronico',
price: 'BRL 400,00',
description: 'Descrição 4'
}
]
watch(rowSelection, () => console.log('Selected rows: ', rowSelection.value))
watch(pagination, () => console.log('Pagination state: ', pagination.value))
watch(activeRow, () => console.log('Active row: ', activeRow.value))
</script>
Data
Use the data prop to create your listing. It could be an array of objects or a function that returns a Promise that resolves with an array.
type ListViewDataRow = {
//...any other properties you may need
id: string,
avatar?: {
alt?: string,
icon?: string,
src?: string,
text?: string
}
}
<template>
<MeListView
:data="provider"
selectable
>
<template #cell="{ row }">
<MeForehead>
<template #leading>
<div class="flex flex-col gap-y-[6px]">
<span class="text-base text-default font-semibold">
{{ row.original.code }} - {{ row.original.name }}
</span>
<span class="text-xs text-muted font-normal">
{{ row.original.description }}
</span>
</div>
</template>
</MeForehead>
</template>
</MeListView>
</template>
<script setup>
function provider() {
const data = [
{
id: '1',
code: '123',
name: 'Requisição',
description: 'Descrição 1'
},
{
id: '2',
code: '456',
name: 'Cotação',
description: 'Descrição 2'
},
{
id: '3',
code: '789',
name: 'Pedido',
description: 'Descrição 3'
}
]
return new Promise((resolve) => {
setTimeout(() => {
resolve(data)
}, 1500)
})
}
</script>
Pagination
Bound pagination with v-model to control the displayed page index and page size. Pagination is provided by TanStack Table, see Table for more information.
type PaginationState = {
pageIndex: number,
pageSize: number
}
123 - RequisiçãoDescrição 1 | |
456 - CotaçãoDescrição 2 | |
<template>
<MeListView
v-model:pagination="pagination"
:data="data"
selectable
>
<template #cell="{ row }">
<MeForehead>
<template #leading>
<div class="flex flex-col gap-y-[6px]">
<span class="text-base text-default font-semibold">
{{ row.original.code }} - {{ row.original.name }}
</span>
<span class="text-xs text-muted font-normal">
{{ row.original.description }}
</span>
</div>
</template>
</MeForehead>
</template>
</MeListView>
</template>
<script setup>
const pagination = ref({ pageIndex: 0, pageSize: 2 })
const data = [
{
id: 'item1',
code: '123',
name: 'Requisição',
description: 'Descrição 1'
},
{
id: 'item2',
code: '456',
name: 'Cotação',
description: 'Descrição 2'
},
{
id: 'item3',
code: '789',
name: 'Pedido',
description: 'Descrição 3'
},
{
id: 'item4',
code: '101',
name: 'Mercado Eletronico',
description: 'Descrição 4'
}
]
</script>
Selected and active rows
Bound rowSelection and activeRow with v-model to control which rows are selected or activated. Selection and activation are only enabled when selectable and active-behavior props are true, respectively.
type RowSelectionState = Record<string, boolean> // { rowId: boolean (whether or not row is selected) }
const activeRow: string // id of the current active row
123 - RequisiçãoDescrição 1 | |
456 - CotaçãoDescrição 2 | |
789 - PedidoDescrição 3 | |
<template>
<MeListView
v-model:active-row="activeRow"
v-model:row-selection="rowSelection"
:data="data"
selectable
active-behavior
>
<template #cell="{ row }">
<MeForehead>
<template #leading>
<div class="flex flex-col gap-y-[6px]">
<span class="text-base text-default font-semibold">
{{ row.original.code }} - {{ row.original.name }}
</span>
<span class="text-xs text-muted font-normal">
{{ row.original.description }}
</span>
</div>
</template>
</MeForehead>
</template>
</MeListView>
</template>
<script setup>
const activeRow = ref('item2')
const rowSelection = ref({ item1: true })
const data = [
{
id: 'item1',
code: '123',
name: 'Requisição',
description: 'Descrição 1'
},
{
id: 'item2',
code: '456',
name: 'Cotação',
description: 'Descrição 2'
},
{
id: 'item3',
code: '789',
name: 'Pedido',
description: 'Descrição 3'
}
]
</script>
Empty
Use the empty prop to customize the empty state when no data is provided. It accepts all props from Empty (except variant), plus a src field to customize the image.
const empty: Omit<EmptyProps, 'variant' & { src?: string }>
TitleDescription | |
<template>
<MeListView
:empty="{
title: 'Title',
description: 'Description',
actions: [{ label: 'Action' }]
}"
selectable
/>
</template>
Preview
Combine MePreview with MeListView to create a custom preview for each list item.
<template>
<MePreview :preview-config="{ src: '/' }">
<MeListView
:data="data"
:pagination="{ pageIndex: 0, pageSize: 4 }"
active-row="item1"
active-behavior
selectable
>
<template #cell="{ row }">
<MeForehead>
<template #leading>
<div class="flex flex-col gap-y-[6px]">
<span class="text-base text-default font-semibold">
{{ row.original.code }} - {{ row.original.name }}
</span>
<span class="text-xs text-muted font-normal">
{{ row.original.description }}
</span>
</div>
</template>
<template #trailing>
<div class="flex flex-col justify-between items-end h-full">
<span class="text-base text-default font-semibold">
{{ row.original.price }}
</span>
<MeForeheadActionBar
:actions="[
{ icon: 'i-lucide-heart' },
{ icon: 'i-lucide-wand-sparkles' }
]"
:dropdown-items="[
{ label: 'Duplicate', icon: 'i-lucide-copy', onSelect: () => {} },
{ label: 'Delete', icon: 'i-lucide-trash', onSelect: () => {} }
]"
see-more
/>
</div>
</template>
</MeForehead>
</template>
</MeListView>
</MePreview>
</template>
<script setup>
const data = [
{
id: 'item1',
avatar: { text: 'RE' },
code: '123',
name: 'Requisição',
description: 'Descrição 1',
price: 'BRL 100,00'
},
{
id: 'item2',
avatar: { text: 'CO' },
code: '456',
name: 'Cotação',
description: 'Descrição 2',
price: 'BRL 200,00'
},
{
id: 'item3',
avatar: { text: 'PE' },
code: '789',
name: 'Pedido',
description: 'Descrição 3',
price: 'BRL 300,00'
},
{
id: 'item4',
avatar: { alt: 'Default avatar' },
code: '101',
name: 'Mercado Eletronico',
description: 'Descrição 4',
price: 'BRL 400,00'
}
]
</script>
Slots
The block provides the header (scoped { column, header, table }), cell (scoped ({ cell, column, getValue, renderValue, row, table })) and footer slots.
Header slot | |
|---|---|
| Row item1 cell slot | |
| Row item2 cell slot | |
| Row item3 cell slot | |
<template>
<MeListView
:data="data"
selectable
>
<template #header>
Header slot
</template>
<template #cell="{ row }">
Row {{ row.original.id }} cell slot
</template>
<template #footer>
Footer slot
</template>
</MeListView>
</template>
<script setup>
const data = [
{
id: 'item1',
code: '123',
name: 'Requisição',
description: 'Descrição 1'
},
{
id: 'item2',
code: '456',
name: 'Cotação',
description: 'Descrição 2'
},
{
id: 'item3',
code: '789',
name: 'Pedido',
description: 'Descrição 3'
}
]
</script>
API
Props
| Prop | Default | Type |
|---|---|---|
activeBehavior | false | Boolean Enables row activation |
activeRow | '' | String Sets active row, bound with v-model |
data | T[] | () => Promise<T[]> List rows data | |
empty | Omit<EmptyProps, 'variant'> & { src?: string } Empty state configuration. See Empty | |
loading | false | Boolean Sets list to loading state |
loadingColor | 'primary' | 'primary' | 'secondary' | 'success' | 'info' | 'warning' | 'error' | 'neutral' Loading bar color |
loadingAnimation | 'carousel' | 'carousel' | 'carousel-inverse' | 'swing' | 'elastic' Loading bar animation |
pagination | { pageIndex: number, pageSize: number } Pagination state, bound with v-model | |
rowSelection | Record<string, boolean> Selected rows, bound with v-model | |
selectable | false | Boolean Enables row selection |
Slots
| Slot | Type |
|---|---|
cell | { cell, column, getValue, renderValue, row, table } |
empty | {} |
footer | {} |
header | { column, header, table } |