SortHeader
Sortable table column header with direction indicator and hover affordance.
import { SortHeader }from "@/components/ui"
Sortable columns
Full source
The complete component, read from src/components/ui/sort-header.tsx.
sort-header.tsx
"use client";
import { ChevronUp, ChevronDown, ChevronsUpDown } from "lucide-react";
import { cn } from "@/lib/utils";
type SortState = "asc" | "desc" | "none";
interface SortHeaderProps {
label: string;
state: SortState;
onClick: () => void;
}
export function SortHeader({ label, state, onClick }: SortHeaderProps) {
const active = state === "asc" || state === "desc";
return (
<th
scope="col"
aria-sort={state === "asc" ? "ascending" : state === "desc" ? "descending" : "none"}
className={cn(
"px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wider",
active ? "text-text" : "text-text-secondary"
)}
>
<button
type="button"
onClick={onClick}
className="group inline-flex items-center gap-1.5 rounded uppercase tracking-wider text-inherit focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent"
>
{label}
{state === "asc" ? (
<ChevronUp size={13} strokeWidth={2.5} aria-hidden />
) : state === "desc" ? (
<ChevronDown size={13} strokeWidth={2.5} aria-hidden />
) : (
<ChevronsUpDown
size={13}
aria-hidden
className="text-text-tertiary opacity-0 transition-opacity group-hover:opacity-100"
/>
)}
</button>
</th>
);
}