Aller au contenu principal

useTableFixedColumn

Ce hook détecte si le contenu d'un tableau dépasse la largeur visible (c'est-à-dire qu'il est partiellement scrollable horizontalement). Il utilise ResizeObserver et des écouteurs d'événements scroll pour déterminer en temps réel si du contenu est masqué, ce qui permet d'afficher visuellement une indication ou de gérer l'affichage de colonnes fixes.

Retour du hook

Le hook retourne :

TypeDescription
booleantrue si du contenu est caché horizontalement (scroll disponible), false sinon

Paramètres

useTableFixedColumn(ref: RefObject<HTMLTableElement | null>)
ParamètreTypeDescription
refRefObject<HTMLTableElement>Référence React attachée à l'élément table

Utilisation basique

import { useRef } from 'react';
import { useTableFixedColumn } from '@/hooks/use-table-fixed-column';

export function DataTable() {
const tableRef = useRef<HTMLTableElement>(null);
const isFullyScrolled = useTableFixedColumn(tableRef);

return (
<div>
{isFullyScrolled && (
<span style={{ color: 'orange', fontSize: '12px' }}>
→ Scroller pour voir plus de colonnes
</span>
)}

<table ref={tableRef}>
<thead>
<tr>
<th>ID</th>
<th>Nom</th>
<th>Email</th>
<th>Téléphone</th>
<th>Adresse</th>
<th>Ville</th>
<th>Code Postal</th>
</tr>
</thead>
<tbody>
{/* Contenu du tableau */}
</tbody>
</table>
</div>
);
}

Fonctionnement

  1. Détection du parent scrollable : Trouve le parent avec data-radix-scroll-area-viewport (Radix UI)
  2. Calcul du scroll : Compare scrollWidth et offsetWidth pour déterminer s'il y a du contenu caché
  3. Écouteur d'événements : Surveillance les changements de scroll en temps réel
  4. Observation de redimensionnement : Utilise ResizeObserver pour détecter les changements de taille
  5. Débouncing : Utilise un délai de 100ms pour optimiser les performances

Architecture du DOM attendu

Le hook recherche un parent spécifique au scroll area de Radix UI :

<div data-radix-scroll-area-viewport>
<table ref={tableRef}>
<!-- Contenu -->
</table>
</div>

Cas d'usage courants

1. Afficher une indication visuelle

const tableRef = useRef<HTMLTableElement>(null);
const hasHiddenContent = useTableFixedColumn(tableRef);

return (
<div>
{hasHiddenContent && (
<div style={{ fontSize: '12px', color: '#ff9800' }}>
⚠️ Contenu caché horizontalement
</div>
)}
<table ref={tableRef}>...</table>
</div>
);

2. Appliquer un style conditionnel

const tableRef = useRef<HTMLTableElement>(null);
const isScrollable = useTableFixedColumn(tableRef);

return (
<table
ref={tableRef}
style={{
boxShadow: isScrollable ? '20px 0 10px -10px rgba(0,0,0,0.1)' : 'none',
}}
>
{/* Contenu */}
</table>
);

3. Gérer l'affichage d'une colonne fixe

const tableRef = useRef<HTMLTableElement>(null);
const hasHiddenContent = useTableFixedColumn(tableRef);

return (
<div>
<table ref={tableRef}>
<thead>
<tr>
<th style={{ position: hasHiddenContent ? 'sticky' : 'static', left: 0 }}>
ID
</th>
{/* Autres colonnes */}
</tr>
</thead>
</table>
</div>
);

4. Afficher un bouton de scroll

const tableRef = useRef<HTMLTableElement>(null);
const isScrollable = useTableFixedColumn(tableRef);

return (
<div>
{isScrollable && (
<button onClick={() => {
const scrollContainer = tableRef.current?.closest('[data-radix-scroll-area-viewport]');
if (scrollContainer) scrollContainer.scrollLeft += 200;
}}>
→ Voir plus
</button>
)}
<table ref={tableRef}>...</table>
</div>
);

Points importants

  • ⚠️ Le hook recherche un parent avec data-radix-scroll-area-viewport (spécifique à Radix UI)
  • ⚠️ La table doit être directement enfant du scroll area
  • ℹ️ Utilise ResizeObserver pour détecter les redimensionnements
  • ℹ️ Utilise useDebouncedCallback de TanStack React Pacer pour optimiser les performances
  • ✅ Détecte en temps réel les changements de scroll et de redimensionnement
  • ✅ Automatiquement nettoyé lors du unmount du composant

Performance

Le hook est optimisé pour les performances :

  • Débouncing : La fonction de calcul est déclenchée avec un délai de 100ms
  • Event listeners : Supprimés lors du unmount
  • ResizeObserver : Nettoyé automatiquement
  • Minimal re-renders : Les changements d'état sont minimaux

Sources