Tableau - DsfrTable
🌟 Introduction
Le composant DsfrTable est obsolète. Il n’est plus maintenu. Il reste utilisable pour des tableaux simples. Pour tout tableau plus complexe et/ou plus personnalisé, veuillez utiliser le composant DsfrDataTable.
Il est remplacé par le composant DsfrDataTable qui a été enrichi pour répondre aux besoins en matière de tableaux conforme à la version 1.14.3 du DSFR
Bien qu'il soit déconseillé de l'utiliser nous laissons la docmentation.
:::
🛠️ Props
| Nom | Type | Défaut | Obligatoire | Description |
|---|---|---|---|---|
title | string | ✅ | Les en-têtes de votre tableau. | |
headers | Array<string> | [] | Les en-têtes de votre tableau. | |
rows | Array<DsfrTableRowProps | string[] | DsfrTableCellProps[]> | [] | Les données de chaque rangée dans le tableau. | |
rowKey | string | Function | undefined | Une clé unique pour chaque rangée, utilisée pour optimiser la mise à jour du DOM. | |
currentPage | number | 1 | La page actuelle dans la pagination du tableau. | |
resultsDisplayed | number | 10 | Le nombre de résultats affichés par page dans la pagination. |
📡Événements
| Nom | Description |
|---|---|
update:currentPage | Émis lors du changement de la page actuelle. |
🧩 Slots
header: Ce slot permet de personnaliser les en-têtes du tableau. Par défaut, il utiliseDsfrTableHeadersavec les propsheaders.- Slot par défaut: Utilisé pour le corps du tableau. Par défaut, il affiche les rangées de données via
DsfrTableRow.
📝 Exemples
Exemple Basique
vue
<script lang="ts" setup>
import DsfrTable from '../DsfrTable.vue'
</script>
<template>
<DsfrTable
title="Exemple de tableau simple"
:headers="['Nom', 'Age', 'Ville']"
:rows="[
{ rowData: ['Alice', '30', 'Paris'] },
{ rowData: ['Bob', '24', 'Lyon'] },
]"
/>
</template>Exemple utilisant des composants dans les cellules
vue
<script lang="ts" setup>
import type { DsfrTableCellProps, DsfrTableRowProps } from '../DsfrTable.types'
import { getCurrentInstance, ref } from 'vue'
import DsfrTag from '../../DsfrTag/DsfrTag.vue'
import DsfrTable from '../DsfrTable.vue'
getCurrentInstance()?.appContext.app.component('DsfrTag', DsfrTag)
const title = 'Utilisateurs'
const headers = ['Nom', 'Prénom', 'Email', 'Statut']
const rows: (string | DsfrTableRowProps | DsfrTableCellProps | { component: string, [k: string]: unknown })[][] = [
[
'SÖZE',
'Keyser',
'keyser.soze@mastermind.com',
{
component: 'DsfrTag',
label: 'Info',
class: 'info',
},
],
[
'HUNT',
'Ethan',
'ethan.hunt@impossible.com',
{
component: 'DsfrTag',
label: 'Erreur',
class: 'error',
},
],
[
'HOLMES',
'Sherlock',
'sherlock.holmes@whodunit.com',
{
component: 'DsfrTag',
label: 'Succès',
class: 'success',
},
],
[
'JONES',
'Indiana',
'indiana.jones@marshall-college.com',
{
component: 'DsfrTag',
label: 'Info',
class: 'info',
},
],
[
'WAYNE',
'Bruce',
'bruce.wayne@batmail.com',
{
component: 'DsfrTag',
label: 'Erreur',
class: 'error',
},
],
]
const noCaption = true
const currentPage = ref(1)
const resultsDisplayed = 5
</script>
<template>
<DsfrTable
:title="title"
:headers="headers"
:rows="rows"
:no-caption="noCaption"
:current-page="currentPage"
:results-displayed="resultsDisplayed"
/>
</template>
<style scoped>
:deep(.info) {
color: var(--info-425-625);
background-color: var(--info-950-100);
}
:deep(.error) {
color: var(--error-425-625);
background-color: var(--error-950-100);
}
:deep(.success) {
color: var(--success-425-625);
background-color: var(--success-950-100);
}
</style>⚙️ Code source du composant
vue
<script lang="ts" setup>
import type { DsfrTableProps } from './DsfrTable.types'
import type { DsfrTableRowProps } from './DsfrTableRow.vue'
import { computed, ref } from 'vue'
import DsfrTableHeaders from './DsfrTableHeaders.vue'
import DsfrTableRow from './DsfrTableRow.vue'
import { useRandomId } from '@/utils/random-utils'
export type { DsfrTableProps }
const props = withDefaults(defineProps<DsfrTableProps>(), {
headers: () => [],
rows: () => [],
rowKey: undefined,
currentPage: 1,
resultsDisplayed: 10,
})
// Permet aux utilisateurs d'utiliser une fonction afin de charger des résultats au changement de page
const emit = defineEmits<{ (event: 'update:currentPage'): void }>()
const getRowData = (row: DsfrTableProps['rows']) => {
return Array.isArray(row) ? row : (row as unknown as DsfrTableRowProps).rowData
}
const currentPage = ref(props.currentPage)
const selectId = useRandomId('resultPerPage')
const optionSelected = ref(props.resultsDisplayed)
const pageCount = computed(() =>
props.rows.length > optionSelected.value
? Math.ceil(props.rows.length / optionSelected.value)
: 1,
)
const paginationOptions = [5, 10, 25, 50, 100]
const returnLowestLimit = () => currentPage.value * optionSelected.value - optionSelected.value
const returnHighestLimit = () => currentPage.value * optionSelected.value
const truncatedResults = computed(() => {
if (props.pagination) {
return props.rows.slice(returnLowestLimit(), returnHighestLimit())
}
return props.rows
})
const goFirstPage = () => {
currentPage.value = 1
emit('update:currentPage')
}
const goPreviousPage = () => {
if (currentPage.value > 1) {
currentPage.value -= 1
emit('update:currentPage')
}
}
const goNextPage = () => {
if (currentPage.value < pageCount.value) {
currentPage.value += 1
emit('update:currentPage')
}
}
const goLastPage = () => {
currentPage.value = pageCount.value
emit('update:currentPage')
}
</script>
<template>
<div
class="fr-table"
:class="{ 'fr-table--no-caption': noCaption }"
>
<table>
<caption class="caption">
{{ title }}
</caption>
<thead>
<!-- @slot Slot "header" pour les en-têtes du tableau. Sera dans `<thead>` -->
<slot name="header">
<DsfrTableHeaders
v-if="headers && headers.length"
:headers="headers"
/>
</slot>
</thead>
<tbody>
<!-- @slot Slot par défaut pour le corps du tableau. Sera dans `<tbody>` -->
<slot />
<template v-if="rows && rows.length">
<DsfrTableRow
v-for="(row, i) of truncatedResults"
:key="
rowKey && getRowData(row as string[][])
? typeof rowKey === 'string'
? getRowData(row as string[][])?.[headers.indexOf(rowKey)]?.toString()
: rowKey(getRowData(row as string[][]) ?? [])
: i
"
:row-data="getRowData(row as string[][])"
:row-attrs="'rowAttrs' in row ? row.rowAttrs : {}"
/>
</template>
<tr v-if="pagination">
<td :colspan="headers.length">
<div class="flex justify-right">
<div class="self-center">
<label :for="selectId">Résultats par page : </label>
<select
:id="selectId"
v-model="optionSelected"
title="Résultats par page - le nombre résultats est mis à jour dès sélection d’une valeur"
@change="emit('update:currentPage')"
>
<option
v-for="(option, idx) in paginationOptions"
:key="idx"
:value="option"
>
{{ option }}
</option>
</select>
</div>
<div
class="flex ml-1"
aria-live="polite"
aria-atomic="true"
>
<p class="self-center fr-m-0">
Page {{ currentPage }} sur {{ pageCount }}
</p>
</div>
<div class="flex ml-1">
<button
class="fr-icon-arrow-left-s-first-line"
@click="goFirstPage()"
>
<span class="fr-sr-only">Première page du tableau</span>
</button>
<button
class="fr-icon-arrow-left-s-line"
@click="goPreviousPage()"
>
<span class="fr-sr-only">Page précédente du tableau</span>
</button>
<button
class="fr-icon-arrow-right-s-line"
@click="goNextPage()"
>
<span class="fr-sr-only">Page suivante du tableau</span>
</button>
<button
class="fr-icon-arrow-right-s-last-line"
@click="goLastPage()"
>
<span class="fr-sr-only">Dernière page du tableau</span>
</button>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</template>
<style scoped>
.flex {
display: flex;
}
.justify-right {
justify-content: right;
}
.ml-1 {
margin-left: 1rem;
}
.self-center {
align-self: center;
}
</style>ts
import type VIcon from '../VIcon/VIcon.vue'
import type { HTMLAttributes, TdHTMLAttributes, ThHTMLAttributes } from 'vue'
export type DsfrTableRowProps = {
rowData?: (string | Record<string, any>)[]
rowAttrs?: HTMLAttributes
}
export type DsfrTableHeaderProps = {
header?: string
headerAttrs?: ThHTMLAttributes & { onClick?: (e: MouseEvent) => void }
icon?: string | InstanceType<typeof VIcon>['$props']
}
export type DsfrTableHeadersProps = (string | (DsfrTableHeaderProps & { text?: string }))[]
export type DsfrTableCellProps = {
field: string | Record<string, unknown>
cellAttrs?: TdHTMLAttributes
component?: string
text?: string
title?: string
class?: string
onClick?: Promise<void>
}
export type DsfrTableProps = {
title: string
headers?: DsfrTableHeadersProps
rows?: (DsfrTableRowProps | (DsfrTableCellProps | { component: string, [k: string]: unknown } | string)[])[]
rowKey?: ((row: (string | Record<string, any>)[] | undefined) => string | number | symbol | undefined) | string
noCaption?: boolean
pagination?: boolean
currentPage?: number
resultsDisplayed?: number
}