DEV Community

Serif COLAKEL
Serif COLAKEL

Posted on

πŸ”¬ Atomic Design in React and React Native: Building Scalable UI Systems

Tags: React, React Native, Atomic Design, Component Architecture, Best Practices

Atomic Design offers a systematic approach to building maintainable UIs. Let's explore real-world implementations and professional patterns for React and React Native.


οΏ½ Modern Atomic Structure: Enhanced Folder Architecture

Scalable structure with TypeScript and cross-platform support:

src/
β”œβ”€β”€ components/
β”‚   β”œβ”€β”€ atoms/
β”‚   β”‚   β”œβ”€β”€ Button/
β”‚   β”‚   β”‚   β”œβ”€β”€ Button.tsx       # Web implementation
β”‚   β”‚   β”‚   β”œβ”€β”€ Button.native.tsx # Mobile implementation
β”‚   β”‚   β”‚   └── index.ts
β”‚   β”œβ”€β”€ molecules/
β”‚   β”œβ”€β”€ organisms/
β”‚
β”œβ”€β”€ features/             # Optional feature-based grouping
β”‚   └── cart/
β”‚       β”œβ”€β”€ CartItem.tsx  # Feature-specific organism
β”‚
β”œβ”€β”€ theme/
β”‚   β”œβ”€β”€ colors.ts
β”‚   └── spacing.ts
Enter fullscreen mode Exit fullscreen mode

Key improvement: Platform-specific files and feature-based grouping when needed.


πŸ§ͺ Real-World Component Examples

This section showcases practical implementations of atomic design principles in React and React Native.

1. Smart Image Atom (Cross-Platform)

// components/atoms/Image/Image.tsx (Web)
import { useState } from "react";

type ImageProps = {
  src: string;
  fallback?: string;
  alt: string;
  className?: string;
};

export const Image = ({ src, fallback, alt, className }: ImageProps) => {
  const [source, setSource] = useState(src);

  const handleError = () => {
    if (fallback) setSource(fallback);
  };

  return (
    <img
      src={source}
      alt={alt}
      className={className}
      onError={handleError}
      loading="lazy"
    />
  );
};

// components/atoms/Image/Image.native.tsx (Mobile)
import { Image as RNImage } from "react-native";

export const Image = ({ src, fallback, style }) => (
  <RNImage
    source={{ uri: src }}
    defaultSource={fallback}
    style={style}
    accessibilityRole="image"
  />
);
Enter fullscreen mode Exit fullscreen mode

Features:

  • Lazy loading (web)
  • Error fallback
  • Accessibility roles
  • Platform-specific optimizations

2. Form Field Molecule with Validation

// components/molecules/FormField/FormField.tsx
import { useState, useEffect } from "react";
import { TextInput, Label, ErrorText } from "../atoms";

type FormFieldProps = {
  label: string;
  type?: "text" | "email" | "password";
  required?: boolean;
  validator?: (value: string) => string | null;
};

export const FormField = ({
  label,
  type = "text",
  validator,
}: FormFieldProps) => {
  const [value, setValue] = useState("");
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    if (validator && value) {
      setError(validator(value));
    }
  }, [value, validator]);

  return (
    <div className="form-field">
      <Label htmlFor={label}>{label}</Label>
      <TextInput
        id={label}
        type={type}
        value={value}
        onChange={(e) => setValue(e.target.value)}
        aria-invalid={!!error}
      />
      {error && <ErrorText>{error}</ErrorText>}
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

Features:

  • Validation system
  • Accessibility labels
  • Reusable across forms
  • Type safety with TypeScript

3. Product Card Organism

// components/organisms/ProductCard/ProductCard.tsx
import { Image, Button, PriceDisplay } from "../../atoms";

type Product = {
  id: string;
  name: string;
  price: number;
  imageUrl: string;
};

export const ProductCard = ({ product }: { product: Product }) => (
  <article className="product-card">
    <Image
      src={product.imageUrl}
      fallback="/product-fallback.jpg"
      alt={product.name}
    />
    <h3>{product.name}</h3>
    <PriceDisplay value={product.price} currency="USD" />
    <Button
      variant="primary"
      onClick={() => addToCart(product.id)}
      aria-label={`Add ${product.name} to cart`}
    >
      Add to Cart
    </Button>
  </article>
);
Enter fullscreen mode Exit fullscreen mode

Features:

  • Composite UI with multiple atoms
  • Type-safe product interface
  • Accessibility labels
  • Consistent styling system

πŸš€ Advanced Patterns & Best Practices

1. State Management Boundaries

// Good practice - Keep atoms stateless
const Counter = ({ count, onIncrement }) => (
  <div>
    <span>{count}</span>
    <Button onClick={onIncrement}>+</Button>
  </div>
);

// Bad practice - Avoid state in atoms
const Counter = () => {
  const [count, setCount] = useState(0);
  return (...);
};
Enter fullscreen mode Exit fullscreen mode

2. Performance Optimization

// Memoize expensive components
import { memo } from "react";

const HeavyList = memo(({ items }) => (
  <ul>
    {items.map((item) => (
      <ListItem key={item.id} {...item} />
    ))}
  </ul>
));
Enter fullscreen mode Exit fullscreen mode

3. Cross-Platform Strategy

// components/atoms/Button/index.ts
export { default as Button } from "./Button";
// Automatically imports .native.tsx for React Native

// Shared props interface
interface ButtonProps {
  variant?: "primary" | "secondary";
  accessibilityLabel?: string;
  onPress: () => void;
}
Enter fullscreen mode Exit fullscreen mode

4. Accessibility First

// components/atoms/IconButton.tsx
export const IconButton = ({ icon, label, ...props }) => (
  <button {...props} aria-label={label} className="icon-button">
    <Icon name={icon} />
  </button>
);
Enter fullscreen mode Exit fullscreen mode

5. Theme Provider Pattern

// theme/ThemeProvider.tsx
import { ThemeProvider as StyledProvider } from "styled-components";

const theme = {
  colors: {
    primary: "#2196F3",
    error: "#FF5252",
  },
  spacing: (multiplier: number) => `${4 * multiplier}px`,
};

export const ThemeProvider = ({ children }) => (
  <StyledProvider theme={theme}>{children}</StyledProvider>
);
Enter fullscreen mode Exit fullscreen mode

πŸ“± React Native Specific Patterns

1. Safe Area Handling

// templates/MainLayout.native.tsx
import { SafeAreaView } from "react-native";

export const MainLayout = ({ children }) => (
  <SafeAreaView style={styles.container}>
    <Header />
    {children}
  </SafeAreaView>
);
Enter fullscreen mode Exit fullscreen mode

2. Touch Interaction Best Practice

// molecules/ListItem.native.tsx
import { Pressable, View } from "react-native";

export const ListItem = ({ title, onPress }) => (
  <Pressable
    onPress={onPress}
    android_ripple={{ color: "#ddd" }}
    style={({ pressed }) => [styles.item, pressed && styles.pressed]}
  >
    <Text>{title}</Text>
  </Pressable>
);
Enter fullscreen mode Exit fullscreen mode

🧠 Architectural Insights

  1. Cross-Platform Metrics
// theme/spacing.ts
export const spacing = {
  base: 8,
  get vertical() {
    return Platform.select({
      web: this.base * 2,
      default: this.base,
    });
  },
};
Enter fullscreen mode Exit fullscreen mode
  1. Feature-Sliced Structure
features/
  authentication/
    components/
      LoginForm.tsx
    hooks/
      useAuth.ts
Enter fullscreen mode Exit fullscreen mode
  1. Documentation Strategy
/**
 * @component FormField
 * @description Reusable form input with validation
 * @prop {string} label - Input label
 * @prop {function} validator - Validation function
 * @example
 * <FormField
 *   label="Email"
 *   validator={(v) => isValidEmail(v) ? null : 'Invalid email'}
 * />
 */
Enter fullscreen mode Exit fullscreen mode

🏁 Conclusion

By implementing these real-world patterns:

βœ… Achieve true cross-platform consistency
βœ… Build maintainable component systems
βœ… Enhance team collaboration
βœ… Improve testability
βœ… Future-proof your architecture

Atomic Design is not just a patternβ€”it's a mindset that helps teams scale their UIs in a systematic and consistent way. Whether you're building for web or mobile, applying this approach in React and React Native can dramatically improve your component architecture.

Top comments (1)

Collapse
Β 
nevodavid profile image
Nevo David β€’

insane depth here, i honestly wish i had this when i started building my first real project