Focus on solving the most common use cases (the 95%) exceptionally well rather than over-engineering for rare specializations (the 5%). Common elements include buttons, tables, cards, sidebars, charts, forms, modals, and notifications.
Avoid complex abstractions for simple problems. A developer should be able to modify a component (like changing a label) without unwrapping multiple layers of abstraction. Use direct, obvious, and complete implementations for common tasks.
// WRONG — solves a hypothetical future problem with excessive abstraction
<DataTable
columns={columns}
data={data}
sortable
filterable
paginated
exportable
selectable
onRowClick={handleRowClick}
onSelectionChange={handleSelection}
renderCustomCell={(cell) => <CustomCell {...cell} />}
/>
// RIGHT — solves the actual problem using direct, composable primitives
<Table>
<TableHeader>...</TableHeader>
<TableBody>
{items.map((item) => (
<TableRow key={item.id}>
<TableCell>{item.name}</TableCell>
<TableCell>{item.status}</TableCell>
</TableRow>
))}
</TableBody>
</Table>