# Code Style and Conventions Standards for Emotion
This document outlines the required code style and conventions for developing with Emotion. Adhering to these standards ensures code maintainability, readability, and performance. These guidelines are tailored to the latest versions of Emotion and aim to promote consistent and effective use of the library.
## 1. General Formatting
### 1.1. Indentation
* **Do This:** Use 2 spaces for indentation.
"""javascript
// Correct indentation
const Button = styled.button"
padding: 10px 20px;
background-color: #007bff;
color: white;
";
"""
* **Don't Do This:** Use tabs or more or less than 2 spaces.
"""javascript
// Incorrect indentation
const Button = styled.button"
padding: 10px 20px;
background-color: #007bff;
color: white;
";
"""
* **Why:** Consistent indentation improves readability and minimizes merge conflicts.
### 1.2. Line Length
* **Do This:** Keep lines under 120 characters. Break longer lines for readability.
"""javascript
// Good: Line broken for readability
const VeryLongComponentName = styled.div"
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 20px;
background-color: #f0f0f0;
";
// Improved styling for enhanced readability and maintainability
const Button = styled.button"
background-color: ${(props) => props.theme.primaryColor};
color: ${(props) => props.theme.textColor};
padding: 1rem 2rem;
border-radius: 5px;
font-size: 1.2rem;
cursor: pointer;
transition: background-color 0.3s ease;
&:hover {
background-color: ${(props) => props.theme.primaryHoverColor};
}
/* Media query for responsiveness */
@media (max-width: 768px) {
font-size: 1rem; /* Adjust font size for smaller screens */
padding: 0.8rem 1.6rem; /* Adjust padding for smaller screens */
}
";
"""
* **Don't Do This:** Allow lines to become excessively long, making code harder to read.
"""javascript
// Bad: Very long line, hard to read
const VeryLongComponentName = styled.div"display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 20px; background-color: #f0f0f0;";
"""
* **Why:** Shorter lines are easier to scan and understand, improving overall code quality.
### 1.3. Whitespace
* **Do This:** Use whitespace to separate logical sections of code, making it easier to read.
"""javascript
// Good: Whitespace used to separate sections
const Header = styled.header"
background-color: #fff;
padding: 20px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
h1 {
font-size: 24px;
margin: 0;
}
";
"""
* **Don't Do This:** Omit whitespace, creating dense and unreadable code.
"""javascript
// Bad: No whitespace, hard to read
const Header = styled.header"background-color: #fff;padding: 20px;box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);h1 {font-size: 24px;margin: 0;}";
"""
* **Why:** Proper whitespace significantly improves readability and comprehension.
### 1.4. File Structure
* **Do This:** Organize Emotion styles in separate files, especially for larger components, and use descriptive names.
"""
// Example file structure
src/
components/
Button/
Button.jsx
Button.styles.js
"""
"""javascript
// Button.styles.js
import styled from '@emotion/styled';
export const StyledButton = styled.button"
/* Styles */
";
"""
* **Don't Do This:** Mix Emotion styles directly within the component files for complex components. This reduces readability and maintainability.
* **Why:** Separation promotes modularity, making it easier to manage and reuse styles.
## 2. Naming Conventions
### 2.1. Component Names
* **Do This:** Use PascalCase for component names.
"""javascript
// Good: PascalCase for component names
const MyComponent = styled.div"
/* Styles */
";
"""
* **Don't Do This:** Use camelCase or snake_case for component names.
"""javascript
// Bad: camelCase or snake_case
const myComponent = styled.div"
/* Styles */
";
"""
* **Why:** PascalCase is a standard convention for React components, promoting consistency across the codebase.
### 2.2. Variable Names
* **Do This:** Use camelCase for variable names, especially for style variables.
"""javascript
// Good: camelCase for variables
const primaryColor = '#007bff';
const Button = styled.button"
background-color: ${primaryColor};
";
"""
* **Don't Do This:** Use PascalCase or snake_case for non-component variable names.
* **Why:** camelCase is a common JavaScript convention, enhancing readability.
### 2.3. CSS Class Names
* **Do This:** When using "css" prop or "cx" (classnames) from "@emotion/css", use BEM (Block, Element, Modifier) naming convention or similar for clarity and specificity.
"""javascript
// Good: BEM naming
import { css } from '@emotion/react';
const block = css"
.block__element {
color: blue;
}
.block__element--modifier {
font-weight: bold;
}
";
"""
* **Don't Do This:** Use generic or ambiguous class names that can clash or are hard to understand.
* **Why:** Naming conventions provide predictability, reusability, and help avoid naming conflicts.
## 3. Styling Approaches
### 3.1. "styled" API
* **Do This:** Use the "styled" API for most component styling as it provides a clean and intuitive way to create styled components.
"""javascript
// Good: Using styled API
import styled from '@emotion/styled';
const Button = styled.button"
padding: 10px 20px;
background-color: #007bff;
color: white;
";
"""
* **Don't Do This:** Overuse inline styles or CSS classes when "styled" components offer a better alternative.
* **Why:** "styled" components encapsulate styles and improve component reusability.
### 3.2. Theming
* **Do This:** Leverage Emotion's theming capabilities to manage consistent styling across your application. Use the "" to inject a theme object.
"""javascript
// Good: Using theming
import styled from '@emotion/styled';
import { ThemeProvider } from '@emotion/react';
const theme = {
primaryColor: '#007bff',
secondaryColor: '#6c757d',
};
const Button = styled.button"
background-color: ${props => props.theme.primaryColor};
color: white;
padding: 10px 20px;
";
function App() {
return (
Click me
);
}
"""
* **Don't Do This:** Hardcode styles throughout your components.
* **Why:** Theming simplifies style management and promotes consistency, and allows for easy modifications (e.g. dark mode).
### 3.3. "css" Prop
* **Do This:** Use the "css" prop for applying dynamic styles or handling complex conditional styling directly on React components.
"""javascript
// Good: Using css prop for dynamic styles
import { css } from '@emotion/react';
function MyComponent({ isPrimary }) {
return (
Hello
);
}
"""
* **Don't Do This:** Overuse "css" prop for static styles when a "styled" component would be more appropriate.
* **Why:** The "css" prop allows for fine-grained control over component styles when needed.
### 3.4. Global Styles
* **Do This:** Define global styles for common elements such as "body", "html", and resets.
"""javascript
// Good: Global styles
import { Global, css } from '@emotion/react';
function App() {
return (
<>
{/* Rest of your app */}
);
}
"""
* **Don't Do This:** Define global styles within individual components, making them harder to maintain.
* **Why:** Global styles provide a consistent base across the application.
### 3.5. Composition & Reusability
* **Do This:** Create reusable style objects and compose them using template literals or styled component composition.
"""javascript
// Good: Reusable style objects
import styled from '@emotion/styled';
import { css } from '@emotion/react';
const baseStyles = css"
padding: 10px 20px;
border-radius: 5px;
";
const PrimaryButton = styled.button"
${baseStyles};
background-color: #007bff;
color: white;
";
const SecondaryButton = styled.button"
${baseStyles};
background-color: #6c757d;
color: white;
";
"""
* **Don't Do This:** Duplicate styles across multiple components.
* **Why:** Reusability reduces code duplication and makes updates easier.
## 4. Specific Emotion Features & Best Practices
### 4.1. Media Queries
* **Do This:** Define media queries using template literals within styled components for responsive designs.
"""javascript
// Good: Media queries
import styled from '@emotion/styled';
const ResponsiveDiv = styled.div"
padding: 20px;
@media (max-width: 768px) {
padding: 10px;
}
";
"""
* **Don't Do This:** Hardcode pixel values without considering responsiveness.
* **Why:** Media queries ensure that your application adapts to different screen sizes.
### 4.2. Pseudo-Selectors
* **Do This:** Use pseudo-selectors like ":hover", ":focus", and ":active" within styled components for interactive styling.
"""javascript
// Good: Pseudo-selectors
import styled from '@emotion/styled';
const Button = styled.button"
padding: 10px 20px;
background-color: #007bff;
color: white;
&:hover {
background-color: #0056b3;
}
";
"""
* **Don't Do This:** Neglect interactive states, leading to a poor user experience.
* **Why:** Pseudo-selectors enhance the interactivity and usability of your components.
### 4.3. Keyframes Animations
* **Do This:** Define keyframes for animations and use them within styled components.
"""javascript
// Good: Keyframes animation
import styled from '@emotion/styled';
import { keyframes } from '@emotion/react';
const rotate = keyframes"
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
";
const Spinner = styled.div"
display: inline-block;
animation: ${rotate} 2s linear infinite;
padding: 20px;
font-size: 1.2rem;
";
"""
* **Don't Do This:** Use inline or untracked animations.
* **Why:** Keyframes allow for complex and reusable animations.
### 4.4. "interpolate" Function (Advanced Use)
* **Do This:** Use the "interpolate" helper when working with complex computed styles to ensure they are properly processed by Emotion:
"""javascript
import styled from '@emotion/styled';
import { interpolate } from '@emotion/unitless';
const StyledBox = styled.div"
width: ${interpolate({
from: 0,
to: 100,
unit: 'px',
})};
background-color: hsla(
${interpolate({
from: 0,
to: 360,
unit: 'deg',
})},
100%,
50%,
1
);
";
"""
* **Don't Do This:** Try to manually concatenate strings for advanced calculations, which might lead to unexpected results in Emotion.
### 4.5. Use "useTheme" Hook
* **Do This:** Use "useTheme" hook instead of context consumer for accessing component theme.
"""jsx
import { useTheme } from '@emotion/react';
const MyComponent = () => {
const theme = useTheme();
// Use theme values
return (
{theme.primaryColor}
);
};
"""
* **Don't Do This:** Using context consumer as it's an older approach.
* **Why:** Improves code readability and conciseness when using themes.
## 5. Performance Considerations
### 5.1. Minimize Dynamic Styles
* **Do This:** Reduce the number of dynamic styles whenever possible. Use CSS classes for static styles and the "css" prop or styled components for dynamic adjustments.
"""javascript
// Good: Using CSS classes for static styles
import styled from '@emotion/styled';
const staticStyles = "
padding: 10px 20px;
border-radius: 5px;
";
const Button = styled.button"
${staticStyles}
background-color: ${props => props.primary ? '#007bff' : '#fff'};
color: ${props => props.primary ? 'white' : '#007bff'};
";
"""
* **Don't Do This:** Overuse dynamic styles, as they can lead to performance bottlenecks.
* **Why:** Static styles are more performant because they don't require recalculation on every render.
### 5.2. Avoid Inline Functions in "css" Prop
* **Do This:** Define styles outside of the component when possible or use "useMemo" if styles are derived from props and needed within the component.
"""javascript
// Good: Styles defined outside
import { css } from '@emotion/react';
import React, { useMemo } from 'react';
const myStyles = css"
padding: 20px;
background-color: #f0f0f0;
";
function MyComponent() {
return Hello;
}
const MyComponent = ({ bgColor }) => {
const styles = useMemo(() => css"background-color: ${bgColor};", [bgColor]);
return Hello;
}
"""
* **Don't Do This:** Define inline functions directly in the "css" prop, as it creates new styles on every render.
* **Why:** Defining styles outside the component or using "useMemo" avoids unnecessary style recalculations.
### 5.3. CSS Vendor Prefixing (Generally Handled by Emotion)
* **Do This (Implicit):** Configure your build process (e.g., using Autoprefixer with your build tools) to automatically handle vendor prefixes. Emotion generally handles this but ensure your build setup supports it.
* **Don't Do This (Generally):** Manually add vendor prefixes (e.g., "-webkit-", "-moz-") to your CSS unless absolutely necessary and you know Emotion isn't handling it.
* **Why:** Autoprefixer (or similar tools) automatically adds necessary prefixes, reducing manual effort and ensuring compatibility across different browsers. Emotion often integrates with such tools.
## 6. Security Considerations
### 6.1. Sanitize User Inputs
* **Do This:** Sanitize any user-provided data before using it in styles to prevent CSS injection attacks.
"""javascript
// Good: Sanitizing input
import styled from '@emotion/styled';
import { escape } from 'lodash'; // or similar sanitization library
const UserInputDiv = styled.div"
color: ${props => escape(props.textColor)};
";
"""
* **Don't Do This:** Directly use user input in styles without sanitization.
* **Why:** Sanitization prevents malicious users from injecting arbitrary CSS.
### 6.2. Content Security Policy (CSP)
* **Do This:** Configure a Content Security Policy to restrict the sources from which styles can be loaded, mitigating XSS attacks. Ensure that your CSP allows the execution of inline styles and scripts necessary for Emotion to function correctly (using nonces or hashes).
* **Don't Do This:** Have a wide-open CSP that allows styles from any source.
* **Why:** CSP adds an extra layer of security by limiting the sources of content that can be loaded.
### 6.3. Avoid "dangerouslySetInnerHTML" with Styled Components
* **Do This:** If you must use "dangerouslySetInnerHTML" (which is generally discouraged), avoid combining it directly with styled components that accept user-controlled data.
* **Don't Do This:** Render user-supplied content directly into styled components without careful sanitization, as it could lead to XSS vulnerabilities.
* **Why:** Using "dangerouslySetInnerHTML" bypasses React's normal rendering process and can open up security vulnerabilities if not handled carefully.
## 7. Tooling and Automation
### 7.1. Linters and Formatters
* **Do This:** Use linters (like ESLint) and formatters (like Prettier) to automatically enforce code style and formatting. Configure these tools with rules that align with these Emotion coding standards.
* **Don't Do This:** Rely solely on manual code reviews for style enforcement.
* **Why:** Automation ensures consistent code quality across the codebase.
### 7.2. IDE Integration
* **Do This:** Configure your IDE with the necessary plugins and settings to support Emotion development, including syntax highlighting, autocompletion, and linting.
* **Don't Do This:** Use a barebones editor without proper Emotion support.
* **Why:** IDE integration improves developer productivity and reduces errors.
### 7.3. Build Process
* **Do This:** Integrate style extraction and optimization tools into your build process to improve performance. This might include CSS minification, dead code elimination, and critical CSS extraction.
* **Don't Do This:** Skip style optimization steps, which can lead to larger CSS bundles and slower load times.
* **Why:** Optimized styles improve application performance and user experience.
## 8. Documentation and Comments
* **Do This:** Document Emotion-specific logic. If you're doing something unusual, take the time to explain why in a comment.
"""javascript
// Custom logic to adjust line height based on text length for optical balance
const Title = styled.h1"
font-size: 2rem;
/* Adjust line height for better readability, especially with longer titles */
line-height: ${({ textLength }) => textLength > 30 ? '2.5rem' : '2.2rem'};
";
"""
* **Don't Do This:** Assume complexity is self-explanatory. If a piece of Emotion code requires deep knowledge, document it.
* **Why:** Documentation simplifies knowledge sharing and makes code more transparent.
By following these guidelines, you can write clean, maintainable, and performant Emotion code. This will improve collaboration, reduce errors, and ultimately contribute to the success of your projects.
danielsogl
Created Mar 6, 2025
This guide explains how to effectively use .clinerules
with Cline, the AI-powered coding assistant.
The .clinerules
file is a powerful configuration file that helps Cline understand your project's requirements, coding standards, and constraints. When placed in your project's root directory, it automatically guides Cline's behavior and ensures consistency across your codebase.
Place the .clinerules
file in your project's root directory. Cline automatically detects and follows these rules for all files within the project.
# Project Overview project: name: 'Your Project Name' description: 'Brief project description' stack: - technology: 'Framework/Language' version: 'X.Y.Z' - technology: 'Database' version: 'X.Y.Z'
# Code Standards standards: style: - 'Use consistent indentation (2 spaces)' - 'Follow language-specific naming conventions' documentation: - 'Include JSDoc comments for all functions' - 'Maintain up-to-date README files' testing: - 'Write unit tests for all new features' - 'Maintain minimum 80% code coverage'
# Security Guidelines security: authentication: - 'Implement proper token validation' - 'Use environment variables for secrets' dataProtection: - 'Sanitize all user inputs' - 'Implement proper error handling'
Be Specific
Maintain Organization
Regular Updates
# Common Patterns Example patterns: components: - pattern: 'Use functional components by default' - pattern: 'Implement error boundaries for component trees' stateManagement: - pattern: 'Use React Query for server state' - pattern: 'Implement proper loading states'
Commit the Rules
.clinerules
in version controlTeam Collaboration
Rules Not Being Applied
Conflicting Rules
Performance Considerations
# Basic .clinerules Example project: name: 'Web Application' type: 'Next.js Frontend' standards: - 'Use TypeScript for all new code' - 'Follow React best practices' - 'Implement proper error handling' testing: unit: - 'Jest for unit tests' - 'React Testing Library for components' e2e: - 'Cypress for end-to-end testing' documentation: required: - 'README.md in each major directory' - 'JSDoc comments for public APIs' - 'Changelog updates for all changes'
# Advanced .clinerules Example project: name: 'Enterprise Application' compliance: - 'GDPR requirements' - 'WCAG 2.1 AA accessibility' architecture: patterns: - 'Clean Architecture principles' - 'Domain-Driven Design concepts' security: requirements: - 'OAuth 2.0 authentication' - 'Rate limiting on all APIs' - 'Input validation with Zod'
# State Management Standards for Emotion This document outlines the coding standards for managing application state within Emotion-styled React components. It aims to provide clear guidelines for data flow, reactivity, and integration with state management libraries, emphasizing maintainability, performance, and best practices aligned with the latest Emotion features and React ecosystem. ## 1. Choosing a State Management Approach The choice of state management approach significantly impacts the structure, maintainability, and performance of your Emotion-styled application. There is no one-size-fits-all solution; the best approach depends on the complexity, scale, and team familiarity. ### 1.1. React Context API **Use Case:** Simple state management for theming, user context, or localized settings that affect rendering across multiple components without prop drilling. Ideal for application-wide theming integration with Emotion. **Standards:** * **Do This:** Use "React.createContext" to define the context and a provider to wrap the application or relevant subtrees. * **Don't Do This:** Overuse Context for frequently changing state that could introduce unnecessary re-renders. Avoid storing large, complex objects directly in context unless you memoize the provider's value. **Why:** Context API provides a built-in mechanism for dependency injection, simplifying access to global state and facilitating testing. **Code Example:** """jsx // ThemeContext.js import React, { createContext, useState, useContext } from 'react'; import { ThemeProvider } from '@emotion/react'; const ThemeContext = createContext({ theme: 'light', toggleTheme: () => {}, }); export const ThemeProviderWrapper = ({ children }) => { const [theme, setTheme] = useState('light'); const toggleTheme = () => { setTheme(prevTheme => (prevTheme === 'light' ? 'dark' : 'light')); }; const themeValue = { theme, toggleTheme, }; return ( <ThemeContext.Provider value={themeValue}> <ThemeProvider theme={theme === 'light' ? lightTheme : darkTheme}> {children} </ThemeProvider> </ThemeContext.Provider> ); }; export const useTheme = () => useContext(ThemeContext); // lightTheme and darkTheme are defined elsewhere with Emotion theme objects const lightTheme = { colors: { primary: '#007bff', background: '#fff', text: '#000', }, }; const darkTheme = { colors: { primary: '#66b3ff', background: '#333', text: '#fff', }, }; // Component using the theme import React from 'react'; import styled from '@emotion/styled'; import { useTheme } from './ThemeContext'; const Button = styled.button" background-color: ${props => props.theme.colors.primary}; color: ${props => props.theme.colors.text}; padding: 10px; border: none; cursor: pointer; "; const ExampleComponent = () => { const { theme, toggleTheme } = useTheme(); return ( <div> <p>Current theme: {theme}</p> <Button onClick={toggleTheme}>Toggle Theme</Button> </div> ); }; export default ExampleComponent; """ **Anti-Pattern:** Deeply nested context providers without strategies to prevent unnecessary renders when context values are updated. ### 1.2. Redux/Zustand/Recoil **Use Case:** Complex applications that manage a large amount of global state, require centralized logic, and benefit from predictable state updates and time-travel debugging. Suitable for managing application data fetched from APIs, user authentication information, or complex forms. **Standards:** * **Do This:** Use Redux Toolkit for Redux, Zustand's simplicity for smaller projects, or Recoil for fine-grained state subscriptions with React's concurrent mode. Utilize selectors to derive data in selectors to prevent unnecessary component re-renders. * **Don't Do This:** Reach directly into the store from Emotion-styled components. Connect component props directly to the store without memoization and selectors. Overuse global store if component-level state is sufficient. **Why:** Redux/Zustand/Recoil provide a robust and predictable state management solution, especially when dealing with asynchronous actions and complex data dependencies. **Code Example:** """jsx // Redux example with @reduxjs/toolkit import React from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { increment, decrement, selectCount } from './counterSlice'; // Assuming a counter slice import styled from '@emotion/styled'; const CounterDisplay = styled.div" font-size: 20px; margin-bottom: 10px; "; const CounterButton = styled.button" background-color: #4CAF50; /* Green */ border: none; color: white; padding: 10px 20px; text-align: center; text-decoration: none; display: inline-block; font-size: 16px; margin: 4px 2px; cursor: pointer; border-radius: 5px; "; const Counter = () => { const count = useSelector(selectCount); const dispatch = useDispatch(); return ( <div> <CounterDisplay>Count: {count}</CounterDisplay> <CounterButton onClick={() => dispatch(increment())}>Increment</CounterButton> <CounterButton onClick={() => dispatch(decrement())}>Decrement</CounterButton> </div> ); }; export default Counter; // counterSlice.js (Redux Toolkit slice) import { createSlice } from '@reduxjs/toolkit'; export const counterSlice = createSlice({ name: 'counter', initialState: { value: 0, }, reducers: { increment: (state) => { state.value += 1; }, decrement: (state) => { state.value -= 1; }, }, }); export const { increment, decrement } = counterSlice.actions; export const selectCount = (state) => state.counter.value; // Selector export default counterSlice.reducer; """ **Anti-Pattern:** Mutating state directly within Redux reducers or Zustand setters. Deeply nested selectors that are difficult to maintain. ### 1.3. Jotai/Zustand for Simpler Global State **Use Case:** Lightweight global state management with minimal boilerplate, suitable for sharing state across components without the complexity of Redux. **Standards:** * **Do This:** Define atoms (Jotai) or stores (Zustand) with clear roles and responsibilities. Use derived atoms in Jotai for computed values based on other atoms. Utilize selector functions for specific data extractions from Zustand stores. * **Don't Do This:** Create excessively large atoms/stores. Directly mutate atom values/store state outside of the defined update functions. **Why:** Offer a simpler API and reduced bundle size compared to Redux while still providing global state management capabilities optimized for performance. The Reactivity reduces re-renders. **Code Example:** """jsx // Jotai example import React from 'react'; import { useAtom } from 'jotai'; import { atom } from 'jotai'; import styled from '@emotion/styled'; const CounterDisplay = styled.div" font-size: 20px; margin-bottom: 10px; "; const CounterButton = styled.button" background-color: #4CAF50; /* Green */ border: none; color: white; padding: 10px 20px; text-align: center; text-decoration: none; display: inline-block; font-size: 16px; margin: 4px 2px; cursor: pointer; border-radius: 5px; "; const countAtom = atom(0); const Counter = () => { const [count, setCount] = useAtom(countAtom); return ( <div> <CounterDisplay>Count: {count}</CounterDisplay> <CounterButton onClick={() => setCount(count + 1)}>Increment</CounterButton> <CounterButton onClick={() => setCount(count - 1)}>Decrement</CounterButton> </div> ); }; export default Counter; """ **Anti-Pattern:** Using overly complex or nested patterns within Jotai atom definitions. ### 1.4. Component-Level State (useState/useReducer) **Use Case:** Managing state that is local to a specific component or a small, isolated part of the application. Considered the first choice for simple state management. **Standards:** * **Do This:** Prefer "useState" for simpler state management. Use "useReducer" for complex state logic involving multiple sub-values or complex updates. * **Don't Do This:** Lift state unnecessarily into parent components. Use Component-level state for data that needs to be shared across multiple unrelated components. **Why:** Keeps the complexity of state management contained within the component itself, preventing global namespace pollution. **Code Example:** """jsx import React, { useState } from 'react'; import styled from '@emotion/styled'; const ToggleButton = styled.button" background-color: ${props => props.isOn ? '#4CAF50' : '#f44336'}; color: white; padding: 10px 20px; border: none; text-align: center; text-decoration: none; display: inline-block; font-size: 16px; margin: 4px 2px; cursor: pointer; border-radius: 5px; "; const ToggleComponent = () => { const [isOn, setIsOn] = useState(false); return ( <div> <p>Toggle is: {isOn ? 'ON' : 'OFF'}</p> <ToggleButton isOn={isOn} onClick={() => setIsOn(!isOn)}> {isOn ? 'Turn OFF' : 'Turn ON'} </ToggleButton> </div> ); }; export default ToggleComponent; """ **Anti-Pattern:** Duplicating state logic across multiple components instead of extracting into a custom hook. ## 2. Integrating State with Emotion Efficiently connecting chosen state management and Emotion styles is crucial for creating maintainable and performant components. ### 2.1. Using State to Dynamically Apply Styles **Standards:** * **Do This:** Use props derived from state (either component-level or global) directly within Emotion's styled components or "css" prop. Use template literals for cleaner syntax when injecting state values into styles. * **Don't Do This:** Dynamically construct class names based on state. Directly manipulate the DOM or styles outside of Emotion's styling system based on state changes. **Why:** Emotion automatically handles CSS injection and updates, reducing manual DOM manipulations and improving performance. **Code Example:** """jsx import React from 'react'; import styled from '@emotion/styled'; const Button = styled.button" background-color: ${props => props.isActive ? 'green' : 'red'}; color: white; padding: 10px 15px; border: none; cursor: pointer; "; const EnhancedButton = ({ isActive, children }) => { return <Button isActive={isActive}>{children}</Button>; }; export default EnhancedButton; """ **Anti-Pattern:* Applying styles via "style" prop when equivalent functionality can be achieved using "styled components" or "css" prop with state variable interpolation. ### 2.2. Theme Provider Integration **Standards:** * **Do This:** Wrap your application with Emotion's "<ThemeProvider>" and manage the theme as part of your application state. Use a state management library that integrates well with React Context, such as Zustand (for simple theme management) or Redux (for complex scenarios). * **Don't Do This:** Hardcode theme values directly into your Emotion-styled components. Place "<ThemeProvider>" inside individual/leaf components since Emotion themes should be application-wide. **Why:** Enables consistent theming across the application and simplifies theme switching based on user preferences or other contextual factors. **Code Example:** """jsx // App.jsx import React, { useState } from 'react'; import styled, { ThemeProvider } from '@emotion/react'; // Define Themes const lightTheme = { colors: { background: '#fff', text: '#000', }, }; const darkTheme = { colors: { background: '#000', text: '#fff', }, }; const Container = styled.div" background-color: ${props => props.theme.colors.background}; color: ${props => props.theme.colors.text}; padding: 20px; "; function App() { const [theme, setTheme] = useState(lightTheme); const toggleTheme = () => { setTheme(theme === lightTheme ? darkTheme : lightTheme); }; return ( <ThemeProvider theme={theme}> <Container> <h1>Themed App</h1> <button onClick={toggleTheme}>Toggle Theme</button> </Container> </ThemeProvider> ); } export default App; """ **Anti-Pattern:** Using multiple "<ThemeProvider>" instances with conflicting themes. ## 3. Performance Considerations Managing state efficiently in combination with Emotion styles is essential for minimizing re-renders and ensuring optimal application performance. ### 3.1. Memoization Techniques **Standards:** * **Do This:** Utilize "React.memo" to prevent re-renders of Emotion-styled components when their props haven't changed. Create memoized selectors using libraries like Reselect for Redux or derived atoms in Jotai/Zustand when using derived data in Emotion styles. * **Don't Do This:** Overuse "React.memo" without profiling potential performance gains vs. the cost of equality checks. **Why:** Memoization avoids unnecessary style re-applications and reduces the overall rendering workload, especially in large applications. **Code Example:** """jsx import React, { memo } from 'react'; import styled from '@emotion/styled'; const ButtonStyled = styled.button" background-color: ${props => props.color}; color: white; padding: 10px 15px; border: none; cursor: pointer; "; const Button = memo(ButtonStyled, (prevProps, nextProps) => { // Custom comparison function. Only re-render if 'color' prop changes. return prevProps.color === nextProps.color; }); export default Button; """ **Anti-Pattern:** Creating inline functions as props to memoized components, as this will always trigger a re-render due to referential inequality. ### 3.2. Avoiding Unnecessary Re-Renders **Standards:** * **Do This:** Ensure props passed to Emotion-styled components are stable and don't change unnecessarily. Batch state updates using "useState" functional updates or "useReducer" to minimize re-renders. * **Don't Do This:** Update state frequently with the same values. Trigger state updates in "render" methods because this leads to infinite loops. **Why:** Reducing re-renders improves application responsiveness and prevents performance bottlenecks, particularly in complex UI interactions and data visualizations. **Code Example:** """jsx import React, { useState, useCallback } from 'react'; import styled from '@emotion/styled'; const Input = styled.input" padding: 8px; border: 1px solid #ccc; "; const Label = styled.label" margin-right: 10px; "; const MyComponent = () => { const [inputValue, setInputValue] = useState(''); const handleInputChange = useCallback((event) => { setInputValue(event.target.value); }, []); return ( <div> <Label>Enter text:</Label> <Input type="text" value={inputValue} onChange={handleInputChange} /> <p>You entered: {inputValue}</p> </div> ); }; export default MyComponent; """ **Anti-Pattern:** Passing entire state objects as props to Emotion-styled components when only specific properties are needed. ## 4. Security Considerations ### 4.1. Sanitizing User Inputs **Standards:** * **Do This:** Sanitize and validate user inputs before using them to dynamically generate styles. Utilize libraries like DOMPurify to prevent Cross-Site Scripting (XSS) attacks. * **Don't Do This:** Directly inject user-provided data into CSS without proper escaping or sanitization. **Why:** Prevents malicious code from manipulating styles and compromising the application. **Code Example:** """jsx import React from 'react'; import styled from '@emotion/styled'; import DOMPurify from 'dompurify'; const DynamicStyle = styled.div" /* Example of UNSAFE styling, DO NOT DO THIS DIRECTLY! */ /* color: ${props => props.unsafeColor}; */ "; const SafeStyle = styled.div" color: ${props => props.safeColor}; "; const ComponentWithDynamicStyle = ({ userInput }) => { const safeColor = DOMPurify.sanitize(userInput); return ( <div> {/* UNSAFE */} {/* <DynamicStyle unsafeColor={userInput}>This is dynamically styled text</DynamicStyle> */} {/* SAFE */} <SafeStyle safeColor={safeColor}>This is dynamically styled text</SafeStyle> </div> ); }; export default ComponentWithDynamicStyle; """ **Anti-Pattern:** Trusting the user to provide safe CSS values without any form of validation or sanitization. ### 4.2. Preventing CSS Injection Attacks **Standards:** * **Do This:** Implement Content Security Policy (CSP) headers to restrict the sources from which the browser can load resources, mitigating the risk of CSS injection attacks. * **Don't Do This:** Allow external stylesheets or inline styles from untrusted sources. **Why:** Restricts the impact of potentially malicious CSS code by limiting its access to application resources, reducing the attack surface significantly. ## 5. Testing Strategies ### 5.1. Unit Testing Emotion Components with State **Standards:** * **Do This:** Use testing libraries like Jest and React Testing Library to render and interact with Emotion-styled components. Mock state management hooks and providers to isolate components during testing. Assert that styles are applied correctly based on state changes. * **Don't Do This:** Rely solely on snapshot testing without verifying component behavior based on state. Create brittle tests that tightly couple to implementation details. **Why:** Ensures that Emotion-styled components render correctly based on different state scenarios and that style updates are triggered as expected. """jsx // Example Jest test with React Testing Library import React from 'react'; import { render, screen, fireEvent } from '@testing-library/react'; import Counter from './Counter'; // Component defined in previous examples import { Provider } from 'react-redux'; import { configureStore } from '@reduxjs/toolkit'; import counterReducer from './counterSlice'; const store = configureStore({ reducer: { counter: counterReducer, }, }); test('increments the counter on button click', () => { render( <Provider store={store}> <Counter /> </Provider> ); const incrementButton = screen.getByText('Increment'); fireEvent.click(incrementButton); expect(screen.getByText('Count: 1')).toBeInTheDocument(); }); """ Consistent adherence to these standards will promote code maintainability, improve performance, and reduce the risk of potential security vulnerabilities within Emotion-based React applications.
# Testing Methodologies Standards for Emotion This document outlines the testing methodologies standards for developing applications using Emotion. It provides guidelines encompassing unit, integration, and end-to-end testing, tailored specifically for Emotion-based projects. Following these standards ensures maintainable, performant, and reliable code. ## 1. Unit Testing ### 1.1. Importance of Unit Tests Unit tests are crucial for verifying individual components and functions in isolation. They ensure that each part of the system works as expected. Within the context of Emotion, this often means testing components that rely on Emotion for styling. * **Do This:** Write unit tests for all React components that use Emotion for styling, validating rendered styles, and component behavior. * **Don't Do This:** Neglect testing Emotion components under the assumption that CSS-in-JS styling is "just CSS." ### 1.2. Recommended Testing Frameworks and Libraries * **Jest:** A popular JavaScript testing framework. * **React Testing Library:** Provides utility functions that are focused on testing component behavior rather than implementation details. * **@emotion/test-utils:** Utilities from Emotion that support testing styled components, themes, and keyframes. ### 1.3. Unit Testing Guidelines * **Test Focused Components:** Each unit test should focus on a single component or a small, related set of components. * **Mock Dependencies:** Use mocking to isolate the component being tested. * **Clear Assertions:** Use descriptive assertions to clearly define the expected behavior. * **Test All Scenarios:** Test positive, negative, and edge cases to ensure robustness. ### 1.4. Code Examples #### 1.4.1. Testing a Styled Component """jsx // src/components/Button.jsx import styled from '@emotion/styled'; const Button = styled.button" background-color: ${props => props.primary ? 'palevioletred' : 'white'}; color: ${props => props.primary ? 'white' : 'palevioletred'}; font-size: 1em; margin: 1em; padding: 0.25em 1em; border: 2px solid palevioletred; border-radius: 3px; "; export default Button; """ """jsx // src/components/Button.test.jsx import React from 'react'; import { render, screen } from '@testing-library/react'; import Button from './Button'; describe('Button Component', () => { it('renders with default styles', () => { render(<Button>Click me</Button>); const buttonElement = screen.getByText('Click me'); expect(buttonElement).toHaveStyle('background-color: white'); expect(buttonElement).toHaveStyle('color: palevioletred'); }); it('renders with primary styles', () => { render(<Button primary>Click me</Button>); const buttonElement = screen.getByText('Click me'); expect(buttonElement).toHaveStyle('background-color: palevioletred'); expect(buttonElement).toHaveStyle('color: white'); }); }); """ * **Explanation:** This example demonstrates how to test a styled component, by checking background and color properties. "screen.getByText" is used to find the element, and "toHaveStyle" checks the css. #### 1.4.2. Testing a Component with Theme Provider """jsx // src/components/ThemedButton.jsx import React from 'react'; import styled from '@emotion/styled'; import { useTheme } from '@emotion/react'; const ThemedButton = styled.button" background-color: ${props => props.theme.colors.primary}; color: ${props => props.theme.colors.secondary}; font-size: 1em; margin: 1em; padding: 0.25em 1em; border: 2px solid ${props => props.theme.colors.primary}; border-radius: 3px; "; export default ThemedButton; """ """jsx // src/components/ThemedButton.test.jsx import React from 'react'; import { render, screen } from '@testing-library/react'; import { ThemeProvider } from '@emotion/react'; import ThemedButton from './ThemedButton'; const theme = { colors: { primary: 'darkblue', secondary: 'white', }, }; describe('ThemedButton Component', () => { it('renders with theme styles', () => { render( <ThemeProvider theme={theme}> <ThemedButton>Click me</ThemedButton> </ThemeProvider> ); const buttonElement = screen.getByText('Click me'); expect(buttonElement).toHaveStyle('background-color: darkblue'); expect(buttonElement).toHaveStyle('color: white'); }); }); """ * **Explanation:** When testing components that consume a theme provided by Emotion's "<ThemeProvider>", you need to wrap the component within "<ThemeProvider>" in your test setup. This ensures the component receives the expected theme context. #### 1.4.3. Testing with "as" Prop """jsx // src/components/LinkButton.jsx import styled from '@emotion/styled'; import { Link } from 'react-router-dom'; const LinkButton = styled.button" /* Styles for the button */ background-color: lightblue; color: black; padding: 10px 20px; border: none; cursor: pointer; /* Common styles */ &:hover { background-color: darkblue; color: white; } " const StyledLinkButton = styled(Link)" /* Inherits styles from Button */ ${LinkButton} text-decoration: none; "; export default StyledLinkButton; """ """jsx // src/components/LinkButton.test.jsx import React from 'react'; import { render, screen } from '@testing-library/react'; import { BrowserRouter } from 'react-router-dom'; // Import BrowserRouter import StyledLinkButton from './LinkButton'; describe('StyledLinkButton Component', () => { it('renders as a link with correct styles', () => { render( <BrowserRouter> {/* Wrap with BrowserRouter */} <StyledLinkButton to="/test">Click me</StyledLinkButton> </BrowserRouter> ); const linkElement = screen.getByRole('link', { name: 'Click me' }); expect(linkElement).toHaveStyle('background-color: lightblue'); expect(linkElement).toHaveAttribute('href', '/test'); }); }); """ * **Explanation:** A common pattern is using the "as" prop which allows you to render a styled component as a different HTML element or React component. If rendering a "<Link>" component from "react-router-dom" it is essential to wrap the component under test in a "<BrowserRouter>". ### 1.5. Common Anti-Patterns * **Testing Implementation Details:** Tests should focus on the component's behavior, not its internal implementation. * **Lack of Assertions:** Every test must include assertions to confirm the expected outcome. * **Ignoring Edge Cases:** Failing to test edge cases can lead to unexpected bugs in production. ## 2. Integration Testing ### 2.1. Purpose of Integration Tests Integration tests verify the interaction between different parts of the system. They ensure that components work together correctly. In Emotion-based projects, this means testing the interaction between styled components, themes, and other React components. * **Do This:** Write integration tests for components that interact with other components, the Emotion theme, or external APIs. * **Don't Do This:** Skip integration tests for complex components that rely on multiple dependencies. ### 2.2. Strategies for Integration Testing * **Top-Down:** Start with high-level components and gradually integrate lower-level components. * **Bottom-Up:** Start with low-level components and gradually integrate higher-level components. * **Sandwich:** A combination of top-down and bottom-up approaches. ### 2.3. Integration Testing Guidelines * **Minimal Mocks:** Use mocks sparingly to focus on the integration between actual components. * **Real Data:** Use realistic data to simulate real-world scenarios. * **Test Key Interactions:** Focus on testing the most critical interactions between components. ### 2.4. Code Examples #### 2.4.1. Testing Component Integration with Theme and Styled Components """jsx // src/components/ComplexComponent.jsx import React from 'react'; import styled from '@emotion/styled'; import { useTheme } from '@emotion/react'; const StyledContainer = styled.div" background-color: ${props => props.theme.colors.background}; padding: 20px; "; const Title = styled.h2" color: ${props => props.theme.colors.primary}; "; function ComplexComponent({ title, children }) { const theme = useTheme(); return ( <StyledContainer> <Title>{title}</Title> <div>{children}</div> </StyledContainer> ); } export default ComplexComponent; """ """jsx // src/components/ComplexComponent.test.jsx import React from 'react'; import { render, screen } from '@testing-library/react'; import { ThemeProvider } from '@emotion/react'; import ComplexComponent from './ComplexComponent'; const theme = { colors: { primary: 'darkblue', secondary: 'white', background: 'lightgray', }, }; describe('ComplexComponent Integration', () => { it('renders with theme styles and child content', () => { render( <ThemeProvider theme={theme}> <ComplexComponent title="My Title"> <p>Some content</p> </ComplexComponent> </ThemeProvider> ); const container = screen.getByRole('div'); expect(container).toHaveStyle('background-color: lightgray'); const titleElement = screen.getByText('My Title'); expect(titleElement).toHaveStyle('color: darkblue'); const contentElement = screen.getByText('Some content'); expect(contentElement).toBeInTheDocument(); }); }); """ * **Explanation:** This test checks how "ComplexComponent" renders with different styles. It makes sure a child is being rendered properly as well. ### 2.5. Common Anti-Patterns * **Over-Mocking:** Mocks should be used sparingly. Test the real interactions between components where possible. * **Ignoring Boundary Conditions:** Test how components behave at the boundaries of their expected input ranges. * **Complex Setups:** Keep test setups as simple as possible to reduce the risk of test failures due to unrelated issues. ## 3. End-to-End (E2E) Testing ### 3.1. Purpose of E2E Tests End-to-end tests simulate real user scenarios, verifying that the entire application works correctly from the user's perspective. They test the integration of all layers, including the UI, backend, and database. * **Do This:** Write E2E tests for critical user flows, such as login, form submission, and data retrieval. * **Don't Do This:** Rely solely on unit and integration tests; E2E tests catch issues related to the entire system working together. ### 3.2. Recommended Frameworks and Libraries * **Cypress:** A popular E2E testing framework. * **Playwright:** Another E2E testing framework gaining popularity. ### 3.3. E2E Testing Guidelines * **Real User Scenarios:** Tests should closely mimic real user behavior. * **Stable Test Data:** Use consistent test data to avoid flaky tests. * **Clear Assertions:** Use descriptive assertions to validate the expected outcome. * **Isolate Environments:** Run E2E tests in a dedicated testing environment. ### 3.4. Code Examples #### 3.4.1. Cypress E2E Test """javascript // cypress/e2e/spec.cy.js describe('My First Test', () => { it('Visits the app root url', () => { cy.visit('/'); cy.contains('h1', 'Welcome'); }); it('Verify button navigates to another page', () => { cy.visit('/'); cy.get('button').contains('Go to About').click(); cy.url().should('include', '/about'); cy.contains('h1', 'About Us'); }); }); """ * **Explanation:** This example visits the application and verifies the existance of a "<h1/>" tag with the text of "Welcome." The second test example tests clicking a button, and checking that the url subsequently contains "/about" and that the correct page title is displayed. ### 3.5. Common Anti-Patterns * **Flaky Tests:** Unstable tests that pass and fail intermittently. * **Over-Reliance on UI Selectors:** Prefer using data-* attributes for selectors to make tests more robust. * **Slow Tests:** Optimize tests for speed by minimizing setup and teardown overhead. * **Ignoring Accessibility:** Tests should also verify that the application is accessible. ## 4. Testing Emotion-Specific Features ### 4.1. Keyframes When testing components that use keyframes, it is important to verify that the animation is correctly applied and behaves as expected. """jsx // src/components/AnimatedComponent.jsx import React from 'react'; import styled, { keyframes } from '@emotion/styled'; const rotate = keyframes" from { transform: rotate(0deg); } to { transform: rotate(360deg); } "; const AnimatedDiv = styled.div" display: inline-block; animation: ${rotate} 2s linear infinite; padding: 2rem 1rem; font-size: 1.2rem; "; export default AnimatedDiv; """ """jsx // src/components/AnimatedComponent.test.jsx import React from 'react'; import { render, screen } from '@testing-library/react'; import AnimatedDiv from './AnimatedComponent'; describe('AnimatedDiv Component', () => { it('applies the rotate animation', () => { render(<AnimatedDiv>Rotating Content</AnimatedDiv>); const animatedDiv = screen.getByText('Rotating Content'); expect(animatedDiv).toHaveStyleRule('animation', expect.stringContaining('rotate')); }); }); """ * **Explanation:** Keyframes can be tested by assertion using "toHaveStyleRule" and testing if the final html element has the rotation animation applied. ### 4.2. Global Styles Test if global styles are correctly applied to the document. """jsx // src/components/GlobalStyles.jsx import React from 'react'; import { Global, css } from '@emotion/react'; const GlobalStyles = () => ( <Global styles={css" body { font-family: 'Arial, sans-serif'; background-color: #f0f0f0; } "} /> ); export default GlobalStyles; """ """jsx // src/components/GlobalStyles.test.jsx import React from 'react'; import { render, screen, cleanup } from '@testing-library/react'; import GlobalStyles from './GlobalStyles'; describe('GlobalStyles Component', () => { afterEach(cleanup); it('applies global styles', () => { render(<GlobalStyles />); expect(document.body).toHaveStyle('font-family: Arial, sans-serif'); expect(document.body).toHaveStyle('background-color: #f0f0f0'); }); }); """ * **Explanation:** Similar to keyframes you can verify properties using "toHaveStyle" after rendering. Note the use of "cleanup" to prevent style bleeding between tests. ### 4.3. Testing with "css" prop Emotion’s "css" prop allows you to pass CSS directly to React components. """jsx // src/components/CssPropComponent.jsx import React from 'react'; function CssPropComponent({ children }) { return ( <div css={{ backgroundColor: 'lightblue', padding: '10px', borderRadius: '5px', }} > {children} </div> ); } export default CssPropComponent; """ """jsx // src/components/CssPropComponent.test.jsx import React from 'react'; import { render, screen } from '@testing-library/react'; import CssPropComponent from './CssPropComponent'; describe('CssPropComponent', () => { it('renders with styles from css prop', () => { render(<CssPropComponent>Hello</CssPropComponent>); const divElement = screen.getByText('Hello').closest('div'); expect(divElement).toHaveStyle('background-color: lightblue'); expect(divElement).toHaveStyle('padding: 10px'); }); }); """ * **Explanation:** Test components using the "css" prop in a similar way to testing styled components, using "toHaveStyle". "closest('div')" is used to check the style of the parent div. ## 5. Advanced Testing Techniques ### 5.1. Visual Regression Testing Visual regression testing involves capturing screenshots of components and comparing them to baseline images to detect unintended visual changes. This approach is especially useful for ensuring that styling changes do not introduce visual regressions. * **Tools:** * **Storybook:** Good for creating and managing UI tests * **Chromatic:** Cloud-based visual testing and UI review tool for Storybook. * **Percy:** Visual review platform. ### 5.2. Performance Testing Performance testing measures the rendering performance of Emotion components. This helps identify and address performance bottlenecks. * **Techniques:** * **Profiling:** Use browser developer tools to profile component rendering. * **Benchmarking:** Use libraries like "benchmark.js" to measure the performance of specific code snippets. * **Lighthouse:** Evaluate the performance of your components with Lighthouse. ### 5.3. Accessibility Testing Accessibility testing ensures that Emotion components are accessible to users with disabilities. * **Tools:** * **React Axe:** Adds accessibility testing directly into your React components. * **WAVE:** Web Accessibility Evaluation Tool. ## 6. Continuous Integration (CI) * **Do This:** Integrate testing into your CI/CD pipeline. * **Don't Do This:** Manually run tests only before deployment. ### 6.1. Integrating Testing into CI/CD * **Automated Testing:** Run unit, integration, and E2E tests automatically on every commit and pull request. * **Reporting:** Generate test reports and display them in your CI/CD pipeline. * **Failure Handling:** Fail the build if any tests fail. ## 7. Conclusion Adhering to these testing methodologies standards will help ensure the quality, reliability, and maintainability of Emotion-based applications. By incorporating unit, integration, and end-to-end testing, teams can catch potential issues early in the development process, reduce bugs, and improve the overall user experience. Remember to stay updated with the latest Emotion features and adapt these standards accordingly to leverage new testing capabilities and best practices.
# API Integration Standards for Emotion This document outlines the coding standards for integrating Emotion with external APIs and backend services in React applications. These standards aim to ensure maintainable, performant, secure, and scalable code while leveraging best practices offered by Emotion. ## 1. Architectural Considerations for API Integration with Emotion ### 1.1. Separation of Concerns **Do This:** * Separate API calling logic from presentational components. * Use custom hooks or dedicated service modules for handling API requests. * Style components based on props passed from the connected logic, not directly within the API calling logic itself. **Don't Do This:** * Make API calls directly within Emotion styled components. * Mix API fetching logic with styling logic. * Update the UI directly inside the "fetch" or "axios" calls within the style definition. **Why:** This separation makes components more reusable, testable, and easier to maintain. Components become purely presentational, driven by data, which improves code clarity and reduces side effects. **Example (Anti-Pattern):** """jsx // Avoid this pattern! Mixing API call and styling. import styled from '@emotion/styled'; import { useEffect, useState } from 'react'; const StyledDiv = styled.div" background-color: ${() => { const [data, setData] = useState(null); useEffect(() => { fetch('https://api.example.com/data') .then(response => response.json()) .then(json => setData(json)); }, []); if (data) { return 'lightgreen'; } else { return 'lightcoral'; } }}; padding: 20px; border: 1px solid black; "; function MyComponent() { return <StyledDiv>Data Area</StyledDiv>; } export default MyComponent; """ **Example (Correct Pattern):** """jsx // Correct pattern: Separating API logic and styling. import styled from '@emotion/styled'; import { useData } from './useData'; // Custom hook const StyledDiv = styled.div" background-color: ${props => (props.hasData ? 'lightgreen' : 'lightcoral')}; padding: 20px; border: 1px solid black; "; function MyComponent() { const { data, loading, error } = useData('https://api.example.com/data'); return ( <StyledDiv hasData={!!data}> {loading ? 'Loading...' : error ? 'Error!' : 'Data Area'} </StyledDiv> ); } export default MyComponent; // useData.js (Custom Hook) import { useState, useEffect } from 'react'; export function useData(url) { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { const fetchData = async () => { try { const response = await fetch(url); if (!response.ok) { throw new Error("HTTP error! Status: ${response.status}"); } const json = await response.json(); setData(json); setLoading(false); } catch (e) { setError(e); setLoading(false); } }; fetchData(); }, [url]); return { data, loading, error }; } """ ### 1.2. State Management **Do This:** * Use React Context, Redux, Zustand, or similar state management libraries to store and share fetched data across components. * Consider using React Query or SWR for data fetching, caching, and state synchronization. **Don't Do This:** * Pass API data as props through multiple layers of unrelated components (prop drilling). * Rely solely on component-level state for data that needs to be accessed and updated in multiple places. **Why:** Efficient state management reduces unnecessary re-renders and simplifies data flow, leading to better performance and maintainability. **Example (Using React Context):** """jsx // DataContext.js import React, { createContext, useState, useEffect, useContext } from 'react'; const DataContext = createContext(); export const DataProvider = ({ children }) => { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { const fetchData = async () => { try { const response = await fetch('https://api.example.com/data'); const json = await response.json(); setData(json); } catch (error) { setError(error); } finally { setLoading(false); } }; fetchData(); }, []); const value = { data, loading, error }; return <DataContext.Provider value={value}>{children}</DataContext.Provider>; }; export const useData = () => useContext(DataContext); // MyComponent.js import React from 'react'; import styled from '@emotion/styled'; import { useData } from './DataContext'; const StyledDiv = styled.div" background-color: ${props => (props.hasData ? 'lightgreen' : 'lightcoral')}; padding: 20px; border: 1px solid black; "; function MyComponent() { const { data, loading, error } = useData(); return ( <StyledDiv hasData={!!data}> {loading ? 'Loading...' : error ? 'Error!' : 'Data Area'} </StyledDiv> ); } export default MyComponent; """ ### 1.3 Error Handling **Do This:** * Implement robust error handling to gracefully manage API request failures. * Display user-friendly error messages within Emotion-styled components using conditional rendering. * Log errors to a central logging service for monitoring and debugging. **Don't Do This:** * Ignore potential errors from API requests. * Display raw error messages directly to the user. **Why:** Proper error handling ensures a stable and user-friendly application experience, even when API request fail. Detailed logging enables rapid identification and troubleshooting of issues. **Example:** """jsx import styled from '@emotion/styled'; import { useData } from './useData'; // Custom hook const StyledDiv = styled.div" background-color: ${props => (props.hasData ? 'lightgreen' : 'lightcoral')}; padding: 20px; border: 1px solid black; color: ${props => props.isError ? 'red' : 'black'}; "; const ErrorMessage = styled.p" color: red; font-style: italic; "; function MyComponent() { const { data, loading, error } = useData('https://api.example.com/data'); return ( <StyledDiv hasData={!!data} isError={!!error}> {loading ? 'Loading...' : error ? <ErrorMessage>Error: {error.message}</ErrorMessage> : 'Data Area'} </StyledDiv> ); } export default MyComponent; // useData.js import { useState, useEffect } from 'react'; export function useData(url) { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { const fetchData = async () => { try { const response = await fetch(url); if (!response.ok) { throw new Error("HTTP error! Status: ${response.status}"); } const json = await response.json(); setData(json); setLoading(false); } catch (e) { setError(e); setLoading(false); } }; fetchData(); }, [url]); return { data, loading, error }; } """ ## 2. Best Practices for Connecting to Backend Services ### 2.1. Asynchronous Operations **Do This:** * Use "async/await" syntax for handling asynchronous API calls to improve code readability. * Handle promises correctly using "try...catch" blocks to catch errors. * Display status updates like "Loading..." while waiting for data. **Don't Do This:** * Use ".then()" and ".catch()" chains excessively, as they can make the code harder to read. * Block the UI thread while waiting for API responses. **Why:** "async/await" makes asynchronous code look and behave a bit more like synchronous code, which improves readability and maintainability. **Example:** """jsx import styled from '@emotion/styled'; import { useState, useEffect } from 'react'; const LoadingIndicator = styled.p" font-style: italic; color: grey; "; const StyledDiv = styled.div" padding: 20px; border: 1px solid black; margin-bottom: 10px; "; const ErrorMessage = styled.p" color: red; font-style: italic; "; function AsyncComponent() { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { const fetchData = async () => { try { const response = await fetch('https://api.example.com/data'); if (!response.ok) { throw new Error("HTTP error! status: ${response.status}"); } const jsonData = await response.json(); setData(jsonData); } catch (error) { setError(error); } finally { setLoading(false); } }; fetchData(); }, []); if (loading) { return <LoadingIndicator>Loading data...</LoadingIndicator>; } if (error) { return <ErrorMessage>Error: {error.message}</ErrorMessage>; } return ( <StyledDiv> {data && <p>Data: {JSON.stringify(data)}</p>} </StyledDiv> ); } export default AsyncComponent; """ ### 2.2. Data Transformation **Do This:** * Transform API responses into a format suitable for your styled components. * Centralize transformation logic in helper functions or service modules. **Don't Do This:** * Perform data transformation directly within Emotion styled components. * Pass raw API data directly to styled components without any processing. **Why:** Transformation clarifies and simplifies the data used within styled components, enhancing readability and testability. Reduces the complexity of the styled component definitions. **Example:** """jsx // Transform data to format suitable for styling needs // utils/transformData.js export const transformData = (apiData) => { if (!apiData) return null; return { formattedName: apiData.firstName + ' ' + apiData.lastName, isActive: apiData.status === 'active', profilePicture: apiData.profileImageURL || 'default_image.png' }; }; // MyComponent.js import styled from '@emotion/styled'; import { useState, useEffect } from 'react'; import { transformData } from './utils/transformData'; const ProfileCard = styled.div" background-color: ${props => (props.isActive ? 'lightgreen' : 'lightcoral')}; padding: 15px; border: 1px solid black; border-radius: 8px; "; const ProfileImage = styled.img" width: 50px; height: 50px; border-radius: 50%; margin-right: 10px; "; function MyComponent() { const [data, setData] = useState(null); useEffect(() => { const fetchData = async () => { const response = await fetch('https://api.example.com/user'); const apiData = await response.json(); const transformedData = transformData(apiData); setData(transformedData); }; fetchData(); }, []); if (!data) return <p>Loading...</p>; return ( <ProfileCard isActive={data.isActive}> <ProfileImage src={data.profilePicture} alt="Profile" /> <p>Name: {data.formattedName}</p> </ProfileCard> ); } export default MyComponent; """ ### 2.3. Caching Strategies **Do This:** * Implement caching strategies (e.g., using "localStorage", "sessionStorage", or dedicated caching libraries like "react-query", "swr") to reduce unnecessary API calls. * Use optimistic updates to provide a responsive user experience. **Don't Do This:** * Cache sensitive data without proper encryption and security measures. * Over-cache data that changes frequently. **Why:** Caching improves application performance by reducing latency and network traffic. **Example (Basic LocalStorage Caching):** """jsx import styled from '@emotion/styled'; import { useState, useEffect } from 'react'; const StyledDiv = styled.div" padding: 20px; border: 1px solid black; "; function CachingComponent() { const [data, setData] = useState(null); useEffect(() => { const fetchData = async () => { const cachedData = localStorage.getItem('apiData'); if (cachedData) { setData(JSON.parse(cachedData)); return; // Use cached data if available } const response = await fetch('https://api.example.com/data'); const jsonData = await response.json(); setData(jsonData); localStorage.setItem('apiData', JSON.stringify(jsonData)); // Cache data }; fetchData(); }, []); return ( <StyledDiv> {data ? <p>Data: {JSON.stringify(data)}</p> : <p>Loading...</p>} </StyledDiv> ); } export default CachingComponent; """ ## 3. Integrating Form Submissions With Emotion ### 3.1. Controlled Components **Do This:** * Use controlled components for form inputs to manage input state and validation effectively. * Apply Emotion styles directly on form and form input elements for consistent styling and theming. **Don't Do This:** * Rely on uncontrolled components with direct DOM manipulation for handling form submissions as it reduces maintainability. * Avoid mixing form submission logic directly with style definitions and instead use styles for presentation and custom handlers for form logic. **Why:** Controlled components provide better control over form data, enabling advanced validation and manipulation. Styled-components help you encapsulate styles within reusable and composable components. **Example:** """jsx import styled from '@emotion/styled'; import { useState } from 'react'; const Form = styled.form" display: flex; flex-direction: column; width: 300px; padding: 20px; border: 1px solid #ccc; border-radius: 5px; "; const Input = styled.input" padding: 10px; margin-bottom: 10px; border: 1px solid #ddd; border-radius: 4px; "; const Button = styled.button" padding: 10px 15px; background-color: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer; &:hover { background-color: #0056b3; } "; const Label = styled.label" margin-bottom: 5px; font-weight: bold; "; function MyFormComponent() { const [name, setName] = useState(''); const [email, setEmail] = useState(''); const [message, setMessage] = useState(''); const handleSubmit = async (event) => { event.preventDefault(); try { const response = await fetch('https://api.example.com/submit', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ name, email, message }), }); if (response.ok) { // Handle success alert('Form submitted successfully!'); } else { // Handle error alert('Form submission failed.'); } } catch (error) { console.error('Error submitting form:', error); alert('An error occurred while submitting the form.'); } }; return ( <Form onSubmit={handleSubmit}> <Label htmlFor="name">Name:</Label> <Input type="text" id="name" value={name} onChange={(e) => setName(e.target.value)} required /> <Label htmlFor="email">Email:</Label> <Input type="email" id="email" value={email} onChange={(e) => setEmail(e.target.value)} required /> <Label htmlFor="message">Message:</Label> <Input as="textarea" // Use 'as' prop for textarea id="message" value={message} onChange={(e) => setMessage(e.target.value)} rows="4" required /> <Button type="submit">Submit</Button> </Form> ); } export default MyFormComponent; """ ### 3.2 Validation **Do This:** * Implement client-side and server-side validation to ensure data integrity. * Use appropriate validation libraries like Formik or Yup for complex forms. **Don't Do This:** * Rely solely on client-side validation. Always validate data on the server as well. * Skip validation for performance reasons. **Why:** Validation reduces errors and security vulnerabilities by ensuring that the data meets the application's requirements. ## 4. Security Considerations ### 4.1. Authentication and Authorization **Do This:** * Implement secure authentication and authorization mechanisms to protect API endpoints. * Store tokens securely using HTTP-only cookies or alternative secure storage methods. * Utilize environment variables to store API keys and sensitive credentials. **Don't Do This:** * Store API keys or sensitive data directly in client-side code or version control. * Expose sensitive information in API responses. **Why:** Secure authentication and authorization are essential to protect your application and user data from unauthorized access. ### 4.2. Cross-Origin Resource Sharing (CORS) **Do This:** * Configure CORS on the server-side to allow requests only from authorized domains. * Understand CORS implications when making cross-origin API requests. **Don't Do This:** * Disable CORS completely as it can introduce security risks. * Use wildcard origins ("*") in production CORS configurations. **Why:** Proper CORS configuration prevents malicious websites from accessing your API. ### 4.3. Input Sanitization **Do This:** * Sanitize user inputs to prevent cross-site scripting (XSS) and other injection attacks. * Use appropriate encoding techniques when displaying data in Emotion styled components. **Don't Do This:** * Directly render unsanitized user inputs in styled components. * Trust user-supplied data without proper validation and sanitization. **Why:** Input sanitization is critical for preventing security vulnerabilities and protecting your application from malicious attacks. ## 5. Performance Optimization ### 5.1. Code Splitting **Do This:** * Implement code splitting using React.lazy and Suspense to load components and code related to API integration only when needed. **Why:** Reduces the initial load time and improves overall application performance. ### 5.2. Memoization **Do This:** * Use "React.memo" to memoize Emotion styled components that depend on props retrieved from APIs, preventing unnecessary re-renders. **Why:** Memoization can significantly improve rendering performance. **Example:** """jsx import React from 'react'; import styled from '@emotion/styled'; const StyledDiv = styled.div" padding: 20px; border: 1px solid black; background-color: ${props => (props.isActive ? 'lightgreen' : 'white')}; "; const MemoizedComponent = React.memo(function MyComponent({ data }) { console.log('Component rendered'); // Check rendering return ( <StyledDiv isActive={data.isActive}> Name: {data.name} </StyledDiv> ); }, (prevProps, nextProps) => { // Custom comparison to prevent re-renders if data hasn't changed significantly return prevProps.data.name === nextProps.data.name && prevProps.data.isActive === nextProps.data.isActive; }); export default MemoizedComponent; """ ### 5.3. Debouncing and Throttling : **Do This:** * Apply debouncing or throttling techniques to limit the rates at which API calls are initiated in response to user actions like typing in a search bar or scrolling, reducing server load and improving UI responsiveness. ## 6. Versioning of Endpoints **Do This:** * Incorporate versioning into your API endpoints (e.g., "/api/v1/resource") to maintain compatibility as your API evolves, allowing clients to upgrade at their own pace. * Clearly document any breaking changes introduced in new versions of the API. **Don't Do This:** * Make changes to an API without considering the impact on existing consumers. * Forcing immediate updates for all clients when new features are released. ## Conclusion These standards provide a guide to building robust, maintainable, and secure applications that integrate Emotion with external APIs. By adhering to these guidelines, developers can ensure high-quality code and a consistent development experience.
# Component Design Standards for Emotion This document outlines the component design standards for Emotion, focusing on creating reusable, maintainable, and performant components within the Emotion ecosystem. It serves as a guide for developers and provides context for AI coding assistants. ## 1. Component Architecture ### 1.1. Atomic Design Principles **Standard:** Embrace Atomic Design principles to create a scalable and maintainable component library. * **Why:** Atomic Design provides a structured approach to component creation, promoting reusability, consistency, and easier maintenance. It breaks down the UI into fundamental building blocks that can be combined to create more complex components. * **Do This:** * Identify and create Atoms (smallest indivisible elements like buttons, inputs, labels). * Combine Atoms into Molecules (simple groups of UI elements functioning as a unit, e.g., a search bar consisting of an input and a button). * Assemble Molecules into Organisms (relatively complex sections of the UI, e.g., a product listing with image, title, and price). * Compose Organisms into Templates (page-level layouts defining underlying content structure). * Utilize Templates to construct Pages (specific instances of templates with representative content). * **Don't Do This:** * Create monolithic components that handle too much logic or are difficult to reuse. * Skip the atomic design process and directly create complex components, leading to inconsistencies and maintenance difficulties. * **Code Example:** """jsx // Atom: Button import styled from '@emotion/styled'; const Button = styled.button" background-color: #4CAF50; border: none; color: white; padding: 10px 20px; text-align: center; text-decoration: none; display: inline-block; font-size: 16px; cursor: pointer; border-radius: 5px; &:hover { background-color: #3e8e41; } "; export default Button; // Molecule: Search Bar import React from 'react'; import styled from '@emotion/styled'; import Button from './Button'; const SearchBarContainer = styled.div" display: flex; align-items: center; "; const Input = styled.input" padding: 10px; border: 1px solid #ccc; border-radius: 5px; margin-right: 10px; font-size: 16px; "; const SearchBar = () => { return ( <SearchBarContainer> <Input type="text" placeholder="Search..." /> <Button>Search</Button> </SearchBarContainer> ); }; export default SearchBar; """ ### 1.2. Separation of Concerns **Standard:** Practice a clear separation of concerns by dividing components into presentational and container components. Consider also using hooks for more complex logic. * **Why:** Separating concerns improves code readability, testability, and reusability. Presentational components focus on UI rendering, while container components handle data fetching, state management, and business logic. * **Do This:** * Create presentational components that receive data and callbacks via props and focus solely on rendering UI. * Create container components that manage state, data fetching, and pass necessary data and callbacks to presentational components. * Use hooks where relevant to extract complicated state logic. * **Don't Do This:** * Mix data fetching and business logic within presentational components, making them difficult to test and reuse. * Write overly complex container components that handle UI rendering logic. * **Code Example:** """jsx // Presentational Component: ProductCard.jsx import React from 'react'; import styled from '@emotion/styled'; const Card = styled.div" border: 1px solid #ccc; padding: 15px; margin: 10px; width: 200px; text-align: center; "; const Title = styled.h3" font-size: 18px; margin-bottom: 5px; "; const Price = styled.p" font-weight: bold; "; const ProductCard = ({ product }) => { return ( <Card> <Title>{product.name}</Title> <Price>${product.price}</Price> <img src = {product.image} width = {150} height = {150} alt = {product.name} /> </Card> ); }; export default ProductCard; // Container Component: ProductList.jsx import React, { useState, useEffect } from 'react'; import ProductCard from './ProductCard'; import styled from '@emotion/styled'; const ProductListContainer = styled.div" display: flex; flex-wrap: wrap; justify-content: center; "; const ProductList = () => { const [products, setProducts] = useState([]); useEffect(() => { const fetchProducts = async () => { try { const response = await fetch('https://fakestoreapi.com/products'); const data = await response.json(); setProducts(data); } catch (error) { console.error("Error fetching products:", error); } }; fetchProducts(); }, []); return ( <ProductListContainer> {products.map((product) => ( <ProductCard key={product.id} product={product} /> ))} </ProductListContainer> ); }; export default ProductList; """ ### 1.3. Using Emotion Themes **Standard:** Utilize Emotion's theming capabilities to manage and apply consistent styling across your application * **Why:** Themes offer a centralized way to define and manage styles (colors, fonts, spacing, etc.). This approach ensures consistency, improves maintainability, and simplifies style updates across the application. * **Do This:** * Define a theme object containing your style variables. * Wrap your application with the "<ThemeProvider>" component. * Access theme values within your styled components using the "theme" prop. * **Don't Do This:** * Hardcode style values directly within styled components, making styling updates and consistency difficult to manage. * Avoid defining a comprehensive theme object. Strive to capture all common styling attributes. * **Code Example:** """jsx // theme.js export const theme = { colors: { primary: '#007bff', secondary: '#6c757d', background: '#f8f9fa', text: '#212529', }, fonts: { main: 'Arial, sans-serif', secondary: 'Helvetica, sans-serif', }, spacing: { small: '8px', medium: '16px', large: '24px', }, }; // App.jsx import React from 'react'; import { ThemeProvider } from '@emotion/react'; import styled from '@emotion/styled'; import { theme } from './theme'; const AppContainer = styled.div" background-color: ${props => props.theme.colors.background}; color: ${props => props.theme.colors.text}; font-family: ${props => props.theme.fonts.main}; padding: ${props => props.theme.spacing.medium}; "; const Title = styled.h1" color: ${props => props.theme.colors.primary}; "; const App = () => { return ( <ThemeProvider theme={theme}> <AppContainer> <Title>My Styled Application</Title> <p>Using Emotion's theming capabilities.</p> </AppContainer> </ThemeProvider> ); }; export default App; """ ## 2. Component Implementation ### 2.1. Consistent Styling Approach with "styled" **Standard:** Use the "styled" API for creating styled components. This is the primary and recomended way to create components with Emotion. * **Why:** "styled" provides a clean and declarative approach to styling components, offering better readability and maintainability. It leverages tagged template literals for concise CSS-in-JS syntax. It is the primary way one should write Emotion, and avoids less feature-rich approaches. * **Do This:** * Use "styled.componentName" to create styled components. * Leverage template literals to define CSS rules. * Use props to dynamically style components based on their state or context. * **Don't Do This:** * Use inline styles directly within JSX elements, as this reduces maintainability and reusability. * Overuse global selectors, which can lead to styling conflicts. * **Code Example:** """jsx import styled from '@emotion/styled'; const PrimaryButton = styled.button" background-color: ${props => props.primary ? '#007bff' : '#fff'}; color: ${props => props.primary ? '#fff' : '#007bff'}; border: 1px solid #007bff; padding: 10px 20px; border-radius: 5px; cursor: pointer; &:hover { background-color: ${props => props.primary ? '#0056b3' : '#e9ecef'}; } "; const App = () => { return ( <div> <PrimaryButton primary>Primary Button</PrimaryButton> <PrimaryButton>Secondary Button</PrimaryButton> </div> ); }; """ ### 2.2. Dynamic Styles with Props **Standard:** Utilize component props to dynamically style components based on their state or context. * **Why:** Dynamic styling enables creating versatile components that can adapt to various situations, enhancing reusability and flexibility. * **Do This:** * Access props within styled component definitions to apply conditional styles. * Use ternary operators or logical expressions to handle different styling scenarios. * **Don't Do This:** * Overcomplicate prop-based styling with excessive conditional logic. * Neglect to provide default values for props to avoid unexpected styling issues. * **Code Example:** """jsx import styled from '@emotion/styled'; const StatusIndicator = styled.div" width: 20px; height: 20px; border-radius: 50%; background-color: ${props => { switch (props.status) { case 'online': return 'green'; case 'offline': return 'red'; case 'idle': return 'yellow'; default: return 'gray'; } }}; "; const App = () => { return ( <div> <StatusIndicator status="online" /> <StatusIndicator status="offline" /> <StatusIndicator status="idle" /> <StatusIndicator /> {/* Default: Gray */} </div> ); }; """ ### 2.3. CSS Prop for Overrides (Use Sparingly) **Standard:** Use the "css" prop for simple style overrides or one-off styling adjustments, but avoid relying on it for core component styling. * **Why:** The "css" prop provides a convenient way to apply ad-hoc styles to components without creating new styled components. However, overuse can lead to scattered styles and reduced maintainability. * **Do This:** * Use the "css" prop for minor style adjustments that are specific to a particular instance of a component. * Keep the styles within the "css" prop concise and focused on the specific override. * **Don't Do This:** * Use the "css" prop for defining fundamental component styles; instead, use "styled" components. * Overuse the "css" prop, leading to a lack of consistency and maintainability. * **Code Example:** """jsx import styled from '@emotion/styled'; import { css } from '@emotion/react'; const Button = styled.button" background-color: #007bff; color: white; padding: 10px 20px; border-radius: 5px; cursor: pointer; &:hover { background-color: #0056b3; } "; const App = () => { return ( <div> <Button>Default Button</Button> <Button css={css" margin-left: 10px; font-size: 18px; background-color: #28a745; &:hover { background-color: #1e7e34; } "} > Custom Button </Button> </div> ); }; """ ### 2.4. Composition and Inheritance **Standard:** Combine Emotion components through composition and inheritance to create more complex and specialized components. * **Why:** Composition and inheritance promote code reuse and reduce duplication. This also allows you to create highly customized components that can be shared. * **Do This:** * Use component composition to combine simpler components into more complex ones. * Use Emotion's "styled" API to extend existing styled components and override their styles. * **Don't Do This:** * Create redundant components with overlapping functionality. * Overuse inheritance, which can lead to complex and tightly coupled component hierarchies. * **Code Example:** """jsx import styled from '@emotion/styled'; // Base Button const BaseButton = styled.button" padding: 10px 20px; border-radius: 5px; cursor: pointer; "; // Primary Button (Inheritance) const PrimaryButton = styled(BaseButton)" background-color: #007bff; color: white; border: none; &:hover { background-color: #0056b3; } "; // Outlined Button (Inheritance) const OutlinedButton = styled(BaseButton)" background-color: transparent; color: #007bff; border: 1px solid #007bff; &:hover { background-color: #e9ecef; } "; // Button Group (Composition) const ButtonGroupContainer = styled.div" display: flex; "; const ButtonGroup = ({ children }) => { return <ButtonGroupContainer>{children}</ButtonGroupContainer>; }; const App = () => { return ( <div> <PrimaryButton>Primary</PrimaryButton> <OutlinedButton>Outlined</OutlinedButton> <ButtonGroup> <PrimaryButton>Save</PrimaryButton> <OutlinedButton>Cancel</OutlinedButton> </ButtonGroup> </div> ); }; """ ### 2.5. Avoiding Global Styles (Generally) **Standard:** Minimize the use of global styles in components to maintain encapsulation. If you need global styles use the "Global" component provided by Emotion with intention. * **Why:** Global styles can lead to unintended side effects and styling conflicts across the application. Component-specific styles promote better encapsulation and maintainability. * **Do This:** * Use component-specific styles whenever possible. * If global styles are necessary, use them sparingly and with clear justification. * **Don't Do This:** * Overuse global styles, leading to styling conflicts and reduced maintainability. * Apply global styles indiscriminately. * **Code Example:** """jsx import styled from '@emotion/styled'; import { Global, css } from '@emotion/react'; const AppContainer = styled.div" padding: 20px; "; const Title = styled.h1" color: #333; "; const App = () => { return ( <AppContainer> <Global styles={css" body { font-family: Arial, sans-serif; background-color: #f0f0f0; } "} /> <Title>My Application</Title> <p>Component-specific styles.</p> </AppContainer> ); }; """ ## 3. Performance Considerations ### 3.1. Minimizing Style Re-calculations **Standard:** Strive to minimize style re-calculations by reducing unnecessary prop changes and optimizing component rendering. * **Why:** Excessive style re-calculations can negatively impact performance, especially in complex applications. * **Do This:** * Use "React.memo" to prevent unnecessary re-renders of styled components. * Avoid passing frequently changing props to styled components if they don't affect styling. * Consider using the "useMemo" hook to memoize complex style calculations. * **Don't Do This:** * Pass frequently changing props to styled components without considering their impact on performance. * Rely on excessively complex style calculations within styled components. * **Code Example:** """jsx import styled from '@emotion/styled'; import React, { memo } from 'react'; const StyledButton = styled.button" background-color: ${props => props.primary ? '#007bff' : '#fff'}; color: ${props => props.primary ? '#fff' : '#007bff'}; padding: 10px 20px; border-radius: 5px; cursor: pointer; "; const Button = memo(StyledButton); const App = () => { const [count, setCount] = React.useState(0); return ( <div> <Button primary onClick={() => setCount(count + 1)}> Increment </Button> <p>Count: {count}</p> </div> ); }; """ ### 3.2. Server-Side Rendering (SSR) **Standard:** Implement server-side rendering (SSR) for improved initial page load performance and SEO. * **Why:** SSR delivers pre-rendered HTML to the client, improving perceived performance and enabling search engine crawlers to index the application content effectively. * **Do This:** * Use frameworks like Next.js or Gatsby that provide built-in SSR support for Emotion. * Follow the framework-specific guidelines for configuring Emotion for SSR. * **Don't Do This:** * Neglect to implement SSR for performance-critical applications, missing out on significant rendering optimization. ### 3.3. Code Splitting **Standard:** Use code splitting to reduce the initial JavaScript bundle size and improve load times using Dynamic imports. * **Why:** Code splitting reduces the amount of JavaScript the browser needs to download and parse initially. This is done by breaking up the application into smaller chunks that load on demand. * **Do This:** * Use dynamic imports ("import()") to load components and modules asynchronously. * Structure your application to facilitate code splitting by route or feature. * Ensure that the core of your application loads first. * **Don't Do This:** * Create unnecessarily large bundle sizes. * Implement splitting for components that require immediate availability. * **Code Example:** """jsx import React, { Suspense } from 'react'; import styled from '@emotion/styled'; const LoadableComponent = React.lazy(() => import('./MyComponent')); const LoadingFallback = styled.div" text-align: center; padding: 20px; font-style: italic; "; const App = () => { return ( <div> <Suspense fallback={<LoadingFallback>Loading...</LoadingFallback>}> <LoadableComponent /> </Suspense> </div> ); }; export default App; """ ### 3.4 Vendor Prefixing (Handled by Emotion) **Standard:** Rely on Emotion's built-in vendor prefixing, and avoid manual prefixing. * **Why:** Emotion automatically handles vendor prefixing for CSS properties, ensuring compatibility across different browsers. Manual prefixing can lead to duplication and maintenance issues. * **Do This:** * Write standard CSS properties without vendor prefixes. * Trust Emotion to automatically add the necessary prefixes. * **Don't Do This:** * Manually add vendor prefixes to CSS properties, leading to unnecessary code and potential inconsistencies. ## 4. Accessibility ### 4.1. Semantic HTML **Standard:** Use semantic HTML elements as the foundation for styled components, providing inherent accessibility features. * **Why:** Semantic HTML elements (e.g., "<button>", "<input>", "<nav>", "<article>") provide built-in accessibility features such as proper keyboard navigation, screen reader support, and ARIA roles. * **Do This:** * Use appropriate semantic HTML elements as the base for styled components. * Avoid using generic elements (e.g., "<div>", "<span>") for interactive components where semantic alternatives exist. * **Don't Do This:** * Use non-semantic elements for interactive components, reducing accessibility. * Overuse "<div>" and "<span>" elements without considering semantic alternatives. * **Code Example:** """jsx import styled from '@emotion/styled'; const StyledButton = styled.button" background-color: #007bff; color: white; padding: 10px 20px; border-radius: 5px; cursor: pointer; "; const StyledNav = styled.nav" background-color: #f0f0f0; padding: 10px; "; const StyledLink = styled.a" color: #333; text-decoration: none; margin-right: 10px; "; const App = () => { return ( <div> <StyledButton>Click Me</StyledButton> <StyledNav> <StyledLink href="#">Home</StyledLink> <StyledLink href="#">About</StyledLink> <StyledLink href="#">Contact</StyledLink> </StyledNav> </div> ); }; """ ### 4.2. ARIA Attributes **Standard:** Use ARIA attributes to enhance the accessibility of complex or custom components that lack native semantic equivalents. * **Why:** ARIA attributes provide additional information to assistive technologies, such as screen readers, enabling them to understand the purpose and behavior of non-standard UI elements. * **Do This:** * Add ARIA attributes (e.g., "aria-label", "aria-describedby", "aria-hidden", "role") to components that require additional accessibility information. * Ensure that ARIA attributes are used correctly and do not conflict with existing semantic attributes. * **Don't Do This:** * Overuse ARIA attributes, as this can lead to unnecessary complexity. * Use ARIA attributes incorrectly or redundantly. * Fail to test ARIA attributes with assistive technologies to verify their effectiveness. * **Code Example:** """jsx import styled from '@emotion/styled'; const StyledTooltip = styled.div" position: relative; display: inline-block; "; const TooltipText = styled.span" visibility: hidden; width: 120px; background-color: black; color: #fff; text-align: center; border-radius: 6px; padding: 5px 0; position: absolute; z-index: 1; bottom: 125%; left: 50%; margin-left: -60px; opacity: 0; transition: opacity 0.3s; ${StyledTooltip}:hover & { visibility: visible; opacity: 1; } "; const App = () => { return ( <StyledTooltip aria-label="Tooltip Example"> Hover Me <TooltipText>This is a tooltip</TooltipText> </StyledTooltip> ); }; """ ### 4.3. Color Contrast **Standard:** Ensure sufficient color contrast between text and background colors to meet accessibility guidelines. * **Why:** Insufficient color contrast can make it difficult for users with visual impairments to read text content. * **Do This:** * Use online tools to verify that the color contrast meets WCAG (Web Content Accessibility Guidelines) standards. * Provide alternative high-contrast themes for users with low vision. * Avoid using color alone to convey important information. * **Don't Do This:** * Use color combinations that provide insufficient contrast. * Rely solely on color to differentiate elements. ## 5. Testing ### 5.1. Unit Tests **Standard:** Write unit tests for individual components to ensure they render correctly and behave as expected. * **Why:** Unit tests provide confidence in component functionality and prevent regressions. * **Do This:** * Use testing libraries like Jest and React Testing Library to write unit tests. * Test component rendering with different props and states. * Test component behavior in response to user interactions. * **Don't Do This:** * Neglect to write unit tests for components, leading to potential bugs and regressions. * Write incomplete or superficial unit tests that do not thoroughly test component functionality. ### 5.2. Integration Tests **Standard:** Perform integration tests to ensure components work together correctly within the application context. * **Why:** Integration tests verify that components interact seamlessly and that data flows correctly between them. * **Do This:** * Use tools like Cypress or Selenium to perform integration tests. * Test component interactions within the application's overall structure. * Test data flow between components and external services. * **Don't Do This:** * Skip integration tests, leading to potential issues arising from component interactions. * Neglect to test data flow between components and external services. ### 5.3. Visual Regression Tests **Standard:** Implement visual regression tests to detect unintended visual changes in components. * **Why:** Visual regression tests help prevent accidental styling changes, ensuring consistent UI across different environments. * **Do This:** * Use tools like Storybook and Chromatic to perform visual regression tests. * Capture snapshots of component renderings and compare them against baseline images. * Review and approve any visual changes before merging code. * **Don't Do This:** * Neglect to perform visual regression tests, leading to potential UI inconsistencies. * Approve visual changes without careful review, allowing unintended styling changes to slip through.
# Security Best Practices Standards for Emotion This document outlines security best practices for developing applications using Emotion. It focuses on protecting against common vulnerabilities and implementing secure coding patterns within the Emotion ecosystem. ## 1. Preventing Cross-Site Scripting (XSS) ### 1.1. Understanding XSS Vulnerabilities XSS vulnerabilities allow attackers to inject malicious scripts into web pages viewed by other users. Emotion, by default, provides some protection through its escaping mechanisms, but it's crucial to use them correctly and be aware of potential bypasses, *especially when rendering user-provided or external data*. ### 1.2. Sanitizing User Input **Standard:** Always sanitize user input before rendering it in Emotion components. This includes data from query parameters, form submissions, cookies, and external APIs. **Why:** Prevents malicious scripts from being executed in the user's browser. **Do This:** Use a robust HTML sanitizer library like DOMPurify or sanitize-html. **Don't Do This:** Rely solely on Emotion's default escaping, especially for complex HTML structures. Don't directly insert unsanitized user input into style or HTML attributes. """javascript // Correct: Using DOMPurify to sanitize HTML import DOMPurify from 'dompurify'; import styled from '@emotion/styled'; const UserInput = styled.div" /* Styles here */ "; const MyComponent = ({ userInput }) => { const sanitizedHTML = DOMPurify.sanitize(userInput); return <UserInput dangerouslySetInnerHTML={{ __html: sanitizedHTML }} />; }; export default MyComponent; // Example Usage: // <MyComponent userInput="<h1>Hello</h1><script>alert('XSS');</script>" /> """ """javascript // Anti-pattern: Directly inserting user input without sanitization import styled from '@emotion/styled'; const UserInput = styled.div<{userInput: string}>" /* Styles here */ "; const MyComponent = ({ userInput }) => { // VULNERABLE TO XSS return <UserInput dangerouslySetInnerHTML={{ __html: userInput}} />; }; export default MyComponent; """ ### 1.3. Escaping Special Characters in CSS **Standard:** Always escape special characters in CSS when using dynamic values, particularly when dealing with strings that may contain user-provided data. **Why:** Prevents CSS injection attacks, where attackers can inject malicious CSS code to modify the appearance or behavior of the website. **Do This:** Use Emotion's interpolation features with caution. Use "css" prop or "styled" components with functions. **Don't Do This:** Directly concatenate strings in CSS styles without proper escaping. This is especially dangerous when building dynamic styles based on user input. """javascript // Correct: Using Emotion's interpolation for safe CSS values import styled from '@emotion/styled'; import { css } from '@emotion/react'; const DynamicStyleComponent = styled.div<{ dynamicValue: string }>" color: ${(props) => props.dynamicValue}; /* Other styles */ "; const SafeDynamicStyleComponent = styled.div<{ dynamicValue: string }>" color: ${props => css" ${props.dynamicValue} "}; "; const MyComponent = ({ userInput }) => { const safeColor = userInput; // For demo purposes only. Still needs sanitization if user-controlled. return ( <> <DynamicStyleComponent dynamicValue={safeColor} /> <SafeDynamicStyleComponent dynamicValue={safeColor} /> </> ); }; export default MyComponent; """ """javascript // Anti-pattern: Unsafely concatenating strings in CSS import styled from '@emotion/styled'; const VulnerableComponent = styled.div<{ dynamicValue: string }>" color: ${props => 'red;' + props.dynamicValue}; //Very bad, don't do this! /* Other styles */ "; """ ### 1.4. Attribute Injection Prevention **Standard:** Be very careful when dynamically setting HTML attributes, *especially* "style", "class", and "data-*" attributes. Sanitize data and use React's built-in mechanisms to prevent injection. **Why:** Attackers can inject arbitrary HTML or JavaScript through these attributes, leading to XSS vulnerabilities. **Do This:** * Use "dangerouslySetInnerHTML" **only** after rigorous sanitization with a trusted library like DOMPurify. * Validate and escape data before setting dynamic attributes. * Favour TypeScript or PropTypes to enforce types to minimize type based injection attacks. **Don't Do This:** * Directly inject unsanitized user input into HTML attributes. * Use "dangerouslySetInnerHTML" without careful consideration and sanitization. * Rely on client-side validation alone; always validate on the server as well. """javascript // Correct: Sanitizing before using dangerouslySetInnerHTML import DOMPurify from 'dompurify'; import styled from '@emotion/styled'; const MyComponent = ({ userInput }) => { const sanitizedHTML = DOMPurify.sanitize(userInput, { USE_PROFILES: { html: true } }); return <div dangerouslySetInnerHTML={{ __html: sanitizedHTML }} />; }; export default MyComponent; """ """javascript // Anti-pattern: Directly injecting user input into attributes import styled from '@emotion/styled'; const MyComponent = ({ userInput }) => { //Vulnerable to XSS return <div style={{backgroundImage: "url(${userInput})"}}/> }; export default MyComponent; """ ## 2. Preventing Server-Side Rendering (SSR) Vulnerabilities ### 2.1. Understanding SSR Security Risks When using Emotion with SSR (e.g., Next.js, Gatsby), it's important to be aware of vulnerabilities that arise specifically in the server-side environment. ### 2.2. HTML Injection in SSR **Standard:** Sanitize all user-provided data before including it in the initial HTML generated by the server. **Why:** Prevents malicious scripts injected on the server from being executed during the initial page load. **Do This:** Use DOMPurify. Use content security policies. **Don't Do This:** Directly embed unsanitized data into the string that makes up the HTML. """javascript // Correct: Sanitizing data before rendering in SSR (example with Next.js) import DOMPurify from 'dompurify'; import {GetServerSideProps} from 'next'; import { styled } from '@emotion/styled'; const Title = styled.h1" color: red; "; function HomePage({content}) { return <Title dangerouslySetInnerHTML={{ __html: content }} />; } export const getServerSideProps:GetServerSideProps = async () => { const maliciousContent = "<script>alert('XSS')</script><h1>Hello</h1>"; // Normally from a DB or external source const content = DOMPurify.sanitize(maliciousContent); return { props: {content}, } } export default HomePage """ ### 2.3. Environment Variable Security **Standard:** Never expose sensitive environment variables directly to the client-side code. **Why:** Prevents leaking API keys, database credentials, or other sensitive information. **Do This:** Restrict access to environment variables on the server side. Only pass necessary public information to the client. Use secure configuration management systems for managing environment variables. **Don't Do This:** Directly expose environment variables to the client-side code using "process.env". """javascript // Correct: Using environment variables securely in SSR // Server-side only: const apiKey = process.env.API_KEY; // Client-side (only expose public information): const publicVariable = process.env.NEXT_PUBLIC_APP_NAME; // Must be prefixed with NEXT_PUBLIC_ const ClientComponent = () => { // Can access publicVariable here. return <div>{publicVariable}</div>; }; """ ## 3. Dependency Management and Vulnerability Scanning ### 3.1. Keeping Dependencies Up-to-Date **Standard:** Regularly update your project's dependencies, including Emotion and related libraries, to the latest versions. **Why:** Ensures you have the latest security patches and bug fixes. **Do This:** Use "npm update", "yarn upgrade", or similar commands to update dependencies. Use Dependabot or similar automated dependency update tools. **Don't Do This:** Ignore dependency update notifications or postpone updates indefinitely. ### 3.2. Vulnerability Scanning **Standard:** Integrate vulnerability scanning into your CI/CD pipeline. **Why:** Identifies and alerts you to known vulnerabilities in your dependencies. **Do This:** Use tools like npm audit, yarn audit, or Snyk to scan for vulnerabilities. Fix any identified vulnerabilities promptly. ### 3.3. Resolving Vulnerabilities **Standard:** When vulnerabilities are identified, prioritize patching or upgrading the affected dependencies. If a direct upgrade is not possible, explore workarounds or alternative libraries. **Why:** Mitigates the risk of exploitation from known vulnerabilities. **Do This:** Follow the guidance provided by vulnerability scanning tools to resolve vulnerabilities. ## 4. Content Security Policy (CSP) ### 4.1. Implementing CSP Headers **Standard:** Implement a Content Security Policy (CSP) to control the resources that the browser is allowed to load. **Why:** Reduces the risk of XSS attacks by restricting the sources from which scripts and other resources can be loaded. **Do This:** Configure your server to send CSP headers with appropriate directives. Start with a restrictive policy and gradually relax it as needed. **Don't Do This:** Use a CSP that is too permissive, as it may not provide adequate protection. """javascript // Example CSP header (configure in your server's settings) // Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' https://example.com; style-src 'self' 'unsafe-inline' https://example.com; """ ### 4.2. Emotion and CSP "unsafe-inline" **Standard:** Emotion often requires "unsafe-inline" for styles to work correctly, especially when using dynamic styles. Minimize the use of "unsafe-inline" where possible. **Why:** "unsafe-inline" loosens the CSP and increases the attack surface. **Do This:** * Use nonces with "unsafe-inline". * Consider using "style-src: 'self'" and loading styles from external CSS files where feasible. * Carefully evaluate the need for dynamic styles that require "unsafe-inline". **Don't Do This:** Blindly add "unsafe-inline" without understanding the security implications. ### 4.3. Using Nonces **Standard:** Use nonces (cryptographically secure random values) with "style-src 'nonce-{randomValue}'" to allow inline styles only if they have the correct nonce attribute. **Why:** Limits the execution of inline styles (and scripts) to only those explicitly authorized by the server, mitigating XSS risks. **Do This:** Generate a unique nonce for each request on the server Side. Set the nonce attribute for inline style tags (this has to be done server side before the html is sent). **Don't Do This:** Reuse the same Nonce for subsequent requests. """javascript //Example Server Side code // Example (Next.js server-side rendering) import { v4 as uuidv4 } from 'uuid'; export async function getServerSideProps(context) { const nonce = uuidv4(); context.res.setHeader( 'Content-Security-Policy', "style-src 'self' 'nonce-${nonce}';" ); return { props: { nonce, }, }; } //Example Page Component Side code: import { styled } from '@emotion/styled' const MyStyledComponent = styled.div" color: green; "; function MyPage({ nonce }) { return ( <> <MyStyledComponent /> </> ) } export default MyPage """ ## 5. Secure Coding Practices Specific to Emotion ### 5.1. Careful Use of Global Styles **Standard:** Minimize the use of global styles, especially when dealing with third-party components or user-provided data. **Why:** Global styles can unintentionally affect other parts of the application and increase the risk of CSS conflicts or injection attacks. **Do This:** Prefer scoped styles using styled components or the "css" prop. If global styles are necessary, carefully review their impact on other components and sanitize any dynamic values. ### 5.2. Context API Considerations **Standard:** If you are storing sensitive data in the Emotion context don't store anything that could be used nefariously. **Why:** Prevents leaking or tampering with sensitive information. **Do This:** Only leverage the Context API for theming or component context. Use robust authentication and authorization mechanisms. **Don't Do This:** Store sensitive API keys or auth flows in the Emotion Context Api. ### 5.3. Testing **Standard:** Write tests to verify that your Emotion components are rendering correctly, styles are being applied as expected, and no unexpected behavior is occurring. **Why:** Tests help catch errors early in the development process and prevent regressions. **Do This:** Write unit tests for individual components and integration tests for more complex scenarios. Use tools like Jest and Testing Library to write tests. **Don't Do This:** Skip testing Emotion components altogether. ## 6. Rate limiting ### 6.1 Limiting Request Frequency **Standard:** Implement rate limiting on API endpoints that serve data used or rendered by Emotion components. **Why:** Prevents abuse and denial-of-service (DoS) attacks. **Do This:** Use middleware or libraries to enforce rate limits on your API routes. **Don't Do This:** Allow unrestricted access without rate limiting, especially for data-sensitive endpoints. ## 7. Monitoring and Logging ### 7.1 Implementing Monitoring **Standard:** Implement monitoring to detect and respond to suspicious activity or vulnerabilities in your application. **Why:** Provides visibility into potential security threats and allows for timely remediation. **Do This:** Utilize monitoring tools to track application performance, errors, and security events. Set up alerts for unusual activity. **Don't Do This:** Neglect monitoring, as it hampers your awareness of potential security issues. ### 7.2 Secure Logging **Standard:** Log relevant security events, such as authentication attempts and authorization failures. **Why:** Provides an audit trail for investigating security incidents. **Do This:** Use a secure logging framework and configure logging levels appropriately. Store logs securely and monitor them regularly. **Don't Do This:** Log sensitive data or store logs in plain text without proper security measures. ## 8. Third-Party Components ### 8.1. Auditing Third-Party Components **Standard:** Audit third-party Emotion components or libraries for security vulnerabilities before incorporating them into your project. **Why:** Reduces the risk of introducing security flaws through external code. **Do This:** Review the component's code, check for known vulnerabilities, and ensure it is actively maintained. **Don't Do This:** Blindly trust third-party components without proper evaluation, as they can introduce security risks. By following these security best practices, you can significantly reduce the risk of vulnerabilities in your Emotion applications. Remember that security is an ongoing process, and it's important to stay informed about the latest threats and mitigation techniques.