--- title: Component Style Guidelines and Best Practices sidebar_position: 1 --- # Component Style Guidelines and Best Practices This documentation illustrates how we approach component development in Superset and provides examples to help you in writing new components or updating existing ones by following our community-approved standards. This guide is intended primarily for reusable components. Whenever possible, all new components should be designed with reusability in mind. ## General Guidelines - We use [Ant Design](https://ant.design/) as our component library. Do not build a new component if Ant Design provides one but rather instead extend or customize what the library provides - Always style your component using Emotion and always prefer the theme variables whenever applicable. See: [Emotion Styling Guidelines and Best Practices](./emotion-styling-guidelines) - All components should be made to be reusable whenever possible - All components should follow the structure and best practices as detailed below ## Directory and component structure ``` superset-frontend/src/components {ComponentName}/ index.tsx {ComponentName}.test.tsx {ComponentName}.stories.tsx ``` **Components root directory:** Components that are meant to be re-used across different parts of the application should go in the `superset-frontend/src/components` directory. Components that are meant to be specific for a single part of the application should be located in the nearest directory where the component is used, for example, `superset-frontend/src/Explore/components` **Exporting the component:** All components within the `superset-frontend/src/components` directory should be exported from `superset-frontend/src/components/index.ts` to facilitate their imports by other components **Component directory name:** Use `PascalCase` for the component directory name **Storybook:** Components should come with a storybook file whenever applicable, with the following naming convention `{ComponentName}.stories.tsx`. More details about Storybook below **Unit and end-to-end tests:** All components should come with unit tests using Jest and React Testing Library. The file name should follow this naming convention `{ComponentName}.test.tsx.` Read the [Testing Guidelines and Best Practices](./testing-guidelines) for more details about tests ## Component Development Best Practices ### Use TypeScript All new components should be written in TypeScript. This helps catch errors early and provides better development experience with IDE support. ```tsx interface ComponentProps { title: string; isVisible?: boolean; onClose?: () => void; } export const MyComponent: React.FC = ({ title, isVisible = true, onClose }) => { // Component implementation }; ``` ### Prefer Functional Components Use functional components with hooks instead of class components: ```tsx // ✅ Good - Functional component with hooks export const MyComponent: React.FC = ({ data }) => { const [loading, setLoading] = useState(false); useEffect(() => { // Effect logic }, []); return
{/* Component JSX */}
; }; // ❌ Avoid - Class component class MyComponent extends React.Component { // Class implementation } ``` ### Follow Ant Design Patterns Extend Ant Design components rather than building from scratch: ```tsx import { Button } from 'antd'; import styled from '@emotion/styled'; const StyledButton = styled(Button)` // Custom styling using emotion `; ``` ### Reusability and Props Design Design components with reusability in mind: ```tsx interface ButtonProps { variant?: 'primary' | 'secondary' | 'tertiary'; size?: 'small' | 'medium' | 'large'; loading?: boolean; disabled?: boolean; children: React.ReactNode; onClick?: () => void; } export const CustomButton: React.FC = ({ variant = 'primary', size = 'medium', ...props }) => { // Implementation }; ``` ## Testing Components Every component should include comprehensive tests: ```tsx // MyComponent.test.tsx import { render, screen, fireEvent } from '@testing-library/react'; import { MyComponent } from './MyComponent'; test('renders component with title', () => { render(); expect(screen.getByText('Test Title')).toBeInTheDocument(); }); test('calls onClose when close button is clicked', () => { const mockOnClose = jest.fn(); render(); fireEvent.click(screen.getByRole('button', { name: /close/i })); expect(mockOnClose).toHaveBeenCalledTimes(1); }); ``` ## Storybook Stories Create stories for visual testing and documentation: ```tsx // MyComponent.stories.tsx import type { Meta, StoryObj } from '@storybook/react'; import { MyComponent } from './MyComponent'; const meta: Meta = { title: 'Components/MyComponent', component: MyComponent, parameters: { layout: 'centered', }, tags: ['autodocs'], }; export default meta; type Story = StoryObj; export const Default: Story = { args: { title: 'Default Component', isVisible: true, }, }; export const Hidden: Story = { args: { title: 'Hidden Component', isVisible: false, }, }; ``` ## Performance Considerations ### Use React.memo for Expensive Components ```tsx import React, { memo } from 'react'; export const ExpensiveComponent = memo(({ data }) => { // Expensive rendering logic return
{/* Component content */}
; }); ``` ### Optimize Re-renders Use `useCallback` and `useMemo` appropriately: ```tsx export const OptimizedComponent: React.FC = ({ items, onSelect }) => { const expensiveValue = useMemo(() => { return items.reduce((acc, item) => acc + item.value, 0); }, [items]); const handleSelect = useCallback((id: string) => { onSelect(id); }, [onSelect]); return
{/* Component content */}
; }; ``` ## Accessibility Ensure components are accessible: ```tsx export const AccessibleButton: React.FC = ({ children, onClick }) => { return ( ); }; ``` ## Error Boundaries For components that might fail, consider error boundaries: ```tsx export const SafeComponent: React.FC = ({ children }) => { return ( Something went wrong}> {children} ); }; ```