Skip to content

Instantly share code, notes, and snippets.

@jakeleveroni
Created June 23, 2025 04:46
Show Gist options
  • Select an option

  • Save jakeleveroni/0fd40e07d4c215b26b491465d2d5cb17 to your computer and use it in GitHub Desktop.

Select an option

Save jakeleveroni/0fd40e07d4c215b26b491465d2d5cb17 to your computer and use it in GitHub Desktop.
/*
// init project bun init --react=tailwind
// add this to index.css
@import "tailwindcss";
html {
font-family: sans-serif;
font-size: 14px;
}
table {
border: 1px solid lightgray;
}
tbody {
border-bottom: 1px solid lightgray;
}
th {
border-bottom: 1px solid lightgray;
border-right: 1px solid lightgray;
padding: 2px 4px;
}
tfoot {
color: gray;
}
tfoot th {
font-weight: normal;
}
*/
import { useMemo, useReducer, useRef, useState } from 'react'
import './index.css'
import {
createColumnHelper,
flexRender,
getCoreRowModel,
useReactTable,
} from '@tanstack/react-table'
export type Person = {
firstName: string
lastName: string
age: number
visits: number
status: string
progress: number
}
type Filter = {
name: string;
state: ColumnConfig;
}
type ColumnConfig = Record<keyof Person, boolean>;
const defaultData: Person[] = [
{
firstName: 'tanner',
lastName: 'linsley',
age: 24,
visits: 100,
status: 'In Relationship',
progress: 50,
},
{
firstName: 'tandy',
lastName: 'miller',
age: 40,
visits: 40,
status: 'Single',
progress: 80,
},
{
firstName: 'joe',
lastName: 'dirte',
age: 45,
visits: 20,
status: 'Complicated',
progress: 10,
},
]
const columnHelper = createColumnHelper<Person>()
export function Table() {
const filterNameRef = useRef<HTMLInputElement>(null);
const [data, _setData] = useState(() => [...defaultData])
const [filters, setFilters] = useState<Filter[]>([]);
const [checkboxes, setCheckboxes] = useState<ColumnConfig>({
age: true,
firstName: true,
lastName: true,
progress: true,
status: true,
visits: true,
});
const handleCheckboxChange = (name: keyof Person) => {
setCheckboxes(prev => ({
...prev,
[name]: !prev[name]
}));
};
const columns = useMemo(() => [
...(checkboxes.firstName ? [columnHelper.accessor('firstName', {
cell: info => info.getValue(),
footer: info => info.column.id,
})] : []),
...(checkboxes.lastName ? [columnHelper.accessor('lastName', {
id: 'lastName',
cell: info => <i>{info.getValue()}</i>,
header: () => <span>Last Name</span>,
footer: info => info.column.id,
})] : []),
...(checkboxes.age ? [columnHelper.accessor('age', {
header: () => 'Age',
cell: info => info.renderValue(),
footer: info => info.column.id,
})] : []),
...(checkboxes.visits ? [columnHelper.accessor('visits', {
header: () => <span>Visits</span>,
footer: info => info.column.id,
})] : []),
...(checkboxes.status ? [columnHelper.accessor('status', {
header: 'Status',
footer: info => info.column.id,
})] : []),
...(checkboxes.progress ? [columnHelper.accessor('progress', {
header: 'Profile Progress',
footer: info => info.column.id,
})] : []),
], [checkboxes])
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
})
return (
<div className="flex justify-between p-2">
<div className="p-6 max-w-md mx-auto bg-white rounded-lg shadow-md">
<h2 className="text-xl font-bold mb-4">Select Options</h2>
<div className="space-y-3 mb-4">
{Object.entries(checkboxes).map(([name, checked]) => (
<label key={name} className="flex items-center space-x-3 cursor-pointer">
<input
type="checkbox"
checked={checked}
onChange={() => handleCheckboxChange(name as keyof Person)}
className="w-4 h-4 text-blue-600 rounded focus:ring-blue-500"
/>
<span className="text-gray-700 capitalize">
{name.replace(/([A-Z])/g, ' $1').replace(/^./, str => str.toUpperCase())}
</span>
</label>
))}
</div>
<div className='text-left'>
<h3 className="font-bold text-lg">Filters</h3>
<div className="flex gap-4 py-2" >
{filters.map(x => <button className="appearance-none bg-blue-500 text-white hover:bg-blue-600 p-2 rounded-md hover:bg-gray" onClick={() => setCheckboxes(x.state)}>{x.name}</button>)}
<button className="bg-blue-500 text-white font-bold py-2 px-3 rounded hover:bg-blue-600" onClick={() => setCheckboxes({
age: true,
firstName: true,
lastName: true,
progress: true,
status: true,
visits: true,
})}>
All
</button>
<button className="bg-blue-500 text-white font-bold py-2 px-3 rounded hover:bg-blue-600" onClick={() => setCheckboxes({
age: false,
firstName: false,
lastName: false,
progress: false,
status: false,
visits: false,
})}>
Clear
</button>
</div>
<input className='outline p-2 me-2 rounded-md' type="text" ref={filterNameRef} placeholder="Filter name"/>
<button className="bg-blue-500 text-white font-bold py-2 px-3 rounded hover:bg-blue-600"
onClick={() => setFilters([...filters, { name: filterNameRef.current?.value ?? 'None', state: checkboxes }])}>
Create Filter
</button>
</div>
</div>
<code>
{table.getHeaderGroups()[0].headers.length === 0 && <p>No columns selected</p>}
<table className="min-w-[640px]">
<thead>
{table.getHeaderGroups().map(headerGroup => (
<tr key={headerGroup.id}>
{headerGroup.headers.map(header => (
<th key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</th>
))}
</tr>
))}
</thead>
<tbody>
{table.getRowModel().rows.map(row => (
<tr key={row.id}>
{row.getVisibleCells().map(cell => (
<td key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</td>
))}
</tr>
))}
</tbody>
<tfoot>
{table.getFooterGroups().map(footerGroup => (
<tr key={footerGroup.id}>
{footerGroup.headers.map(header => (
<th key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.footer,
header.getContext()
)}
</th>
))}
</tr>
))}
</tfoot>
</table>
</code>
</div>
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment