콘텐츠로 이동

TableSortLabel — spec

Synthesized from MUI TableSortLabel. The clickable sort indicator inside a header TableCell. Shows the current sort direction (ascending / descending) + click handler to toggle.

When to use

  • Inside header TableCells of sortable columns.
  • For non-sortable columns, render plain text in the TableCell.

API

<TableCell sortDirection={orderBy === 'name' ? order : false}>
  <TableSortLabel
    active={orderBy === 'name'}
    direction={orderBy === 'name' ? order : 'asc'}
    onClick={() => handleSort('name')}
  >
    이름
  </TableSortLabel>
</TableCell>
Prop Type Default Description
active boolean false This column is currently sorted
direction 'asc' \| 'desc' 'asc' Sort direction (ignored when not active)
hideSortIcon boolean false Hide arrow when not active (cleaner default; arrow appears on hover)
IconComponent ElementType ArrowDownwardIcon Custom sort icon
onClick (e) => void Toggle handler

States

State Visual
Default (not active) Label only; no arrow (or arrow on hover if hideSortIcon=false)
Active asc Label + up arrow
Active desc Label + down arrow
Hover (any) Subtle bg + arrow visible
Focus-visible 2px focus ring

Tokens consumed

--icon-size-sm           /* sort arrow */
--color-fg-default
--color-fg-muted         /* inactive arrow */
--motion-duration-100    /* arrow rotation */

Accessibility

  • Renders as <button> — keyboard activates with Enter/Space.
  • Pair with TableCell sortDirection={...} to set aria-sort correctly. MUI handles the cell side automatically.
  • Korean: arrow direction is universal; the label localizes naturally.

Edge cases

  • Tri-state sort (asc → desc → unsorted → asc...) — implement in your onClick. MUI doesn't enforce tri-state by default; common is asc ↔ desc.
  • Multi-column sort — possible but UX-confusing for most adopters. Stick to single-column unless data work warrants it.
  • Default sort — set initial orderBy + order state on mount; first render shows the active arrow.

Code example

function SortableHeader({ orderBy, order, onSort }) {
  const cell = (key, label, align = 'left') => (
    <TableCell
      align={align}
      sortDirection={orderBy === key ? order : false}
      scope="col"
    >
      <TableSortLabel
        active={orderBy === key}
        direction={orderBy === key ? order : 'asc'}
        onClick={() => onSort(key)}
      >
        {label}
      </TableSortLabel>
    </TableCell>
  );

  return (
    <TableHead>
      <TableRow>
        {cell('name', '이름')}
        {cell('department', '부서')}
        {cell('hireDate', '입사일', 'right')}
        {cell('salary', '급여', 'right')}
      </TableRow>
    </TableHead>
  );
}

Don't

  • Don't put TableSortLabel outside a TableCellaria-sort won't propagate.
  • Don't use for non-sortable columns — confuses users when clicking does nothing.
  • Don't omit aria-label if the column header is icon-only (pair with aria-label="정렬: 이름" or similar).

References

Cross-reference