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 
| Nom | Type | Défaut | Obligatoire | Description | 
|---|---|---|---|---|
| header | string | '' | Le texte de l'en-tête du tableau. | |
| headerAttrs | Object | {} | Les attributs HTML supplémentaires pour l'élément <th>. | |
| icon | string | Object | undefined | undefined | L'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 type { DsfrTableHeaderProps } from './DsfrTable.types'
import { computed } from 'vue'
import VIcon from '../VIcon/VIcon.vue'
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 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
}