---
|
description: React coding standards and best practices for the LabelStudio clientside application
|
globs: **/*.jsx,**/*.tsx
|
---
|
|
# React Best Practices
|
|
## Project Structure
|
- All frontend code lives in the `web` directory
|
- Main application code is in `web/apps/labelstudio`
|
- Shared libraries are in `web/libs`
|
- Follow the established directory structure:
|
- `components/`: Reusable UI components
|
- `pages/`: Top-level page components
|
- `utils/`: Utility functions
|
- `hooks/`: Custom React hooks
|
- `atoms/`: Jotai atom state definitions
|
- `providers/`: Context providers
|
- `services/`: API and other services
|
- `types/`: TypeScript type definitions
|
- `assets/`: Static assets
|
|
## Component Structure
|
- Use functional components over class components
|
- Keep components small and focused
|
- Extract reusable logic into custom hooks
|
- Use composition over inheritance
|
- Implement proper prop types with TypeScript
|
- Split large components into smaller, focused ones
|
- Follow a consistent file organization pattern:
|
```
|
component-name/
|
component-name.tsx
|
component-name.module.scss
|
component-name.test.tsx
|
index.ts
|
```
|
|
## Hooks
|
- Follow the Rules of Hooks
|
- Use custom hooks for reusable logic
|
- Keep hooks focused and simple
|
- Avoid useEffect unless absolutely required
|
- Use appropriate dependency arrays in useEffect
|
- Implement cleanup in useEffect when needed
|
- Avoid nested hooks
|
|
## State Management
|
- Use useState for local component state
|
- Use Jotai atoms and not the Context API for shared state
|
- Implement atomWithReducer for complex state logic
|
- Implement atomWithQuery for any API requests for data
|
- Keep state as close to where it's used as possible
|
- Avoid prop drilling through proper state management
|
- Only use Jotai as the single source of truth of global state management
|
|
## Performance
|
- Implement proper memoization (useMemo, useCallback)
|
- Use React.memo for expensive components
|
- Avoid unnecessary re-renders
|
- Implement proper lazy loading
|
- Use proper key props in lists
|
- Profile and optimize render performance
|
|
## Tooling
|
- Use Biome for code linting and formatting
|
- Follow CSS/SCSS linting rules defined in .stylelintrc.json
|
- Use TypeScript for type safety
|
- Keep bundle size in check by monitoring imports
|
|
## Forms
|
- Use controlled components for form inputs
|
- Implement proper form validation
|
- Handle form submission states properly
|
- Show appropriate loading and error states
|
- Use form libraries for complex forms
|
- Implement proper accessibility for forms
|
|
## Error Handling
|
- Implement Error Boundaries
|
- Handle async errors properly
|
- Show user-friendly error messages
|
- Implement proper fallback UI
|
- Log errors appropriately
|
- Handle edge cases gracefully
|
|
## Testing
|
- Write unit tests for components
|
- Implement integration tests for complex flows
|
- Use React Testing Library
|
- Test user interactions
|
- Test error scenarios
|
- Implement proper mock data
|
|
## Accessibility
|
- Ensure components meet WCAG 2.1 AA standards
|
- Use semantic HTML elements
|
- Implement proper ARIA attributes
|
- Ensure keyboard navigation
|
- Test with screen readers
|
- Handle focus management
|
- Provide proper alt text for images
|
|
## Code Organization
|
- Use proper file naming conventions which is kebab-case ie. ListItem -> `list-item.tsx`
|
- Prefer one component per folder, but group related components together when necessary, and ensure there is only one component per file.
|
- Component folders should have a SCSS `.module.scss` with the name of the component kebab-case ie. ListItem -> `list-item.module.scss`
|
- Implement proper directory structure
|
- UI components live within `web/libs/ui`
|
- Application components that are shared across applications such as certain page-level blocks live within `web/libs/app-common`
|
- Code in `web/apps` can only import code from `web/libs` and `web/libs` cannot import from `web/apps`
|
- Code in `web/libs/app-common` can only import code from other `web/libs` or `web/apps`. No other `web/libs` can import from `web/libs/app-common`
|
- Keep atoms in a global atoms folder with the name of the file matching the entity or intent of state
|
- Add all components and their states to Storybook by co-locating the story file next to the component file ie. `list-item.stories.tsx`
|
- Use the `@humansignal/ui` package for UI components
|
- Use the `@humansignal/icons` package for icons
|
- Use the `@humansignal/core` package for core utilities/functions
|
- Use the `@humansignal/app-common` package for application components
|
|
## Best Practices
|
- No cyclic imports
|
- Use proper imports/exports
|
- Follow established import ordering
|
- Compose components rather than extending them
|
- Keep components focused on a single responsibility
|
- Document complex logic with clear comments
|
- Follow the project's folder structure and naming conventions
|
- Prefer controlled components over uncontrolled ones
|