Skip to content

En-tête de tableau - DsfrTableHeader

Enfant de DsfrHeaders (attention au pluriel), DsfrHeader (ici donc au singulier) permet de personnaliser complètement les en-tête de vos tableaux, et il va y mettre une touche de magie !

Parfait pour ajouter du texte et des icônes personnalisées, ce composant est un incontournable pour un tableau élégant et fonctionnel.

🏅 La documentation sur le tableau sur le DSFR

La story sur l’en-tête de tableau sur le storybook de VueDsfr

🛠️ Props

NomTypeDéfautObligatoireDescription
headerstring''Le texte de l'en-tête du tableau.
headerAttrsObject{}Les attributs HTML supplémentaires pour l'élément <th>.
iconstring | Object | undefinedundefinedL'icône à afficher dans l'en-tête. Peut être une chaîne ou un objet pour les icônes personnalisées.

📝 Exemples

Exemple basique

vue
<DsfrTableHeader header="Nom" />

Exemple avec attributs supplémentaires

vue
<DsfrTableHeader
  header="Age"
  :headerAttrs="{ class: 'header-age', id: 'age-header' }"
/>

Exemple avec icône

vue
<DsfrTableHeader
  header="Ville"
  icon="ri-location-pin"
/>

Exemple avec icône

vue
<DsfrTableHeader
  header="Ville"
  icon="fr-icon-mail-line"
/>

Exemple complet

vue
<script lang="ts" setup>
import { computed, ref } from 'vue'

import DsfrTable from '../DsfrTable.vue'
import DsfrTableHeader from '../DsfrTableHeader.vue'

const icon = ref<{ name: string } | undefined>({
  name: 'ri-sort-desc',
})

const header = 'En-tête'
const headerAttrs = computed(() => ({
  class: 'ns-resize',
  onClick: ($event) => {
    $event.preventDefault()
    const iconName = icon.value?.name
    icon.value = iconName === 'ri-sort-desc'
      ? { name: 'ri-sort-asc' }
      : iconName === 'ri-sort-asc'
        ? undefined
        : { name: 'ri-sort-desc' }
  },
}))
</script>

<template>
  <DsfrTable
    title="Titre du tableau"
  >
    <template #header>
      <tr>
        <DsfrTableHeader
          class="flex  justify-between items-center"
          :header="header"
          :header-attrs="headerAttrs"
          :icon="icon"
        />
      </tr>
    </template>
    <tr>
      <td>
        Corps du tableau
      </td>
    </tr>
  </DsfrTable>
</template>

<style scoped>
.ns-resize {
  cursor: ns-resize;
}
.flex {
  display: flex;
}
.justify-between {
  justify-content: space-between;
}
.items-center {
  align-items: center;
}
</style>

⚙️ Code source du composant

vue
<script lang="ts" setup>
import { computed } from 'vue'

import VIcon from '../VIcon/VIcon.vue'

import type { DsfrTableHeaderProps } from './DsfrTable.types'

export type { DsfrTableHeaderProps }

const props = withDefaults(defineProps<DsfrTableHeaderProps>(), {
  header: '',
  headerAttrs: () => ({}),
  icon: undefined,
})

const dsfrIcon = computed(() => {
  return props.icon && typeof props.icon === 'string' && props.icon.startsWith('fr-') ? props.icon : ''
})
const iconProps = computed(() => dsfrIcon.value ? undefined : typeof props.icon === 'string' ? { name: props.icon } : props.icon)
</script>

<template>
  <th
    v-bind="headerAttrs"
    scope="col"
  >
    {{ header }}
    <VIcon
      v-if="icon && !dsfrIcon"
      v-bind="iconProps"
    />
    <span
      v-if="dsfrIcon"
      :class="{ [String(icon)]: dsfrIcon }"
    />
  </th>
</template>
ts
import type { HTMLAttributes, TdHTMLAttributes, ThHTMLAttributes } from 'vue'

import type VIcon from '../VIcon/VIcon.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
}