Boilerplate
Principles
- No over-abstraction — components favor simplicity over excessive composition
- Named exports only — components are always exported as export { Component }
- Consistent naming
- displayName matches the filename
- Filenames are PascalCase (e.g. CursorCard.tsx)
- State conventions
- Use loading instead of isLoading, open instead of isOpen
- The exception is a name the DOM already declares on the element the component renders. checked, prefix and size are all inherited from React's HTML attribute types, so a component that wants them must Omit the inherited one and redeclare — as Checkbox, Input and Textarea do. Never reach for an is/has prefix to dodge the collision; that is what produced isChecked, hasPrefix and the height-that-meant-size before 2.0
- Boolean props that toggle visibility read showX (showLabel, showIcon), so the unprefixed name stays free for the thing itself
- Layout primitives
- Structure built with Flex and Grid
- Interactive styles live in *.module.scss
- Client behavior
- Use "use client" in any component using hooks or state
- Class names
- Use classNames() to merge static and dynamic classes
- Children-first
- Props like children are encouraged for flexibility
Interactivity
- Use ElementType to dynamically render:
- <a>, <button>, NextLink, or layout primitives like Flex
- External links automatically include rel="noopener noreferrer"
Composition
- Use forwardRef for exposing ref
- Spread Flex/Grid props onto the outer wrapper
- Combine className and style props cleanly
- Prefer ReactNode over strings for flexibility and slot-style APIs