← Back to Tutorials Chapter 6

Layout & UI Components

Layout Components Pattern

A layout component is a reusable component that provides the structural skeleton of your application. It handles common UI elements like headers, sidebars, and footers, while rendering the page-specific content via the children prop. This pattern helps maintain a consistent look and feel across different pages.

function Layout({ children, sidebar }) {
  return (
    <div className="app-layout">
      <header className="app-header">
        <h1>My App</h1>
      </header>
      <div className="app-body">
        <aside className="app-sidebar">{sidebar}</aside>
        <main className="app-content">{children}</main>
      </div>
      <footer className="app-footer">
        © 2025 My App
      </footer>
    </div>
  );
}

// Usage
function HomePage() {
  return (
    <Layout sidebar={<NavMenu />}>
      <Dashboard />
    </Layout>
  );
}

Pagination Component

A pagination component is a common UI pattern for displaying large sets of data across multiple pages. It typically includes previous and next buttons along with page number indicators.

function Pagination({ currentPage, totalPages, onPageChange }) {
  const pages = Array.from({ length: totalPages }, (_, i) => i + 1);

  return (
    <div className="pagination">
      <button disabled={currentPage === 1} onClick={() => onPageChange(currentPage - 1)}>
        Previous
      </button>
      {pages.map(page => (
        <button key={page} onClick={() => onPageChange(page)}
                className={page === currentPage ? 'active' : ''}>
          {page}
        </button>
      ))}
      <button disabled={currentPage === totalPages} onClick={() => onPageChange(currentPage + 1)}>
        Next
      </button>
    </div>
  );
}

Material UI

Material UI (MUI) is one of the most popular React UI frameworks. It provides a comprehensive set of components that implement Google's Material Design guidelines. MUI components are production-ready, customizable, and accessible.

import { Button, Grid, AppBar, Toolbar, Typography, Card } from '@mui/material';

function Dashboard() {
  return (
    <div>
      <AppBar position="static">
        <Toolbar>
          <Typography variant="h6">Dashboard</Typography>
        </Toolbar>
      </AppBar>
      <Grid container spacing={3} sx={{ p: 3 }}>
        <Grid item xs={12} sm={6} md={4}>
          <Card sx={{ p: 2 }}>
            <Typography variant="h5">Card 1</Typography>
            <Button variant="contained">Action</Button>
          </Card>
        </Grid>
        <Grid item xs={12} sm={6} md={4}>
          <Card sx={{ p: 2 }}>
            <Typography variant="h5">Card 2</Typography>
            <Button variant="outlined">Action</Button>
          </Card>
        </Grid>
      </Grid>
    </div>
  );
}

React Bootstrap

React Bootstrap is a complete re-implementation of Bootstrap components for React. Unlike the original Bootstrap, React Bootstrap does not rely on jQuery, making it fully compatible with React's declarative approach.

import { Container, Row, Col, Card, Button, Navbar, Nav } from 'react-bootstrap';

function LandingPage() {
  return (
    <div>
      <Navbar bg="dark" variant="dark">
        <Container>
          <Navbar.Brand>MySite</Navbar.Brand>
          <Nav>
            <Nav.Link href="#home">Home</Nav.Link>
            <Nav.Link href="#features">Features</Nav.Link>
          </Nav>
        </Container>
      </Navbar>
      <Container className="mt-4">
        <Row>
          {[1, 2, 3].map(i => (
            <Col md={4} key={i}>
              <Card>
                <Card.Body>
                  <Card.Title>Feature {i}</Card.Title>
                  <Card.Text>Description of feature {i}.</Card.Text>
                  <Button variant="primary">Learn More</Button>
                </Card.Body>
              </Card>
            </Col>
          ))}
        </Row>
      </Container>
    </div>
  );
}

Tables with Sorting

Data tables are a common UI component in dashboard applications. A sortable table allows users to click column headers to sort the data in ascending or descending order.

function SortableTable({ columns, data }) {
  const [sortKey, setSortKey] = useState(null);
  const [sortOrder, setSortOrder] = useState('asc');

  const handleSort = (key) => {
    if (sortKey === key) {
      setSortOrder(order => order === 'asc' ? 'desc' : 'asc');
    } else {
      setSortKey(key);
      setSortOrder('asc');
    }
  };

  const sortedData = useMemo(() => {
    if (!sortKey) return data;
    return [...data].sort((a, b) => {
      const valA = a[sortKey];
      const valB = b[sortKey];
      if (valA < valB) return sortOrder === 'asc' ? -1 : 1;
      if (valA > valB) return sortOrder === 'asc' ? 1 : -1;
      return 0;
    });
  }, [data, sortKey, sortOrder]);

  return (
    <table>
      <thead>
        <tr>
          {columns.map(col => (
            <th key={col.key} onClick={() => handleSort(col.key)} style={{ cursor: 'pointer' }}>
              {col.label} {sortKey === col.key ? (sortOrder === 'asc' ? '▲' : '▼') : ''}
            </th>
          ))}
        </tr>
      </thead>
      <tbody>
        {sortedData.map((row, i) => (
          <tr key={i}>
            {columns.map(col => (
              <td key={col.key}>{row[col.key]}</td>
            ))}
          </tr>
        ))}
      </tbody>
    </table>
  );
}

Integrating Maps with react-leaflet

React Leaflet provides React bindings for Leaflet, a leading open-source interactive map library. It lets you add maps, markers, and geo-layers to your React application using a declarative component API.

import { MapContainer, TileLayer, Marker, Popup } from 'react-leaflet';

function LocationMap({ lat, lng, name }) {
  return (
    <MapContainer center={[lat, lng]} zoom={13} style={{ height: '400px', width: '100%' }}>
      <TileLayer
        url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
        attribution='&copy; OpenStreetMap contributors'
      />
      <Marker position={[lat, lng]}>
        <Popup>{name}</Popup>
      </Marker>
    </MapContainer>
  );
}
React UI component layout

CSS Animations in React

CSS animations can be applied to React components using CSS classes and keyframes. You can toggle animation classes based on component state to create transitions and animated effects.

// CSS (animation.css)
// @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
// .fade-in { animation: fadeIn 0.5s ease-in; }

function AnimatedMessage({ show, message }) {
  return (
    <div className={show ? 'fade-in' : ''} style={{ display: show ? 'block' : 'none' }}>
      {message}
    </div>
  );
}

Framer Motion Basics

Framer Motion is a popular animation library for React. It provides a declarative API for creating animations, gestures, and layout transitions. The motion component extends standard HTML and SVG elements with animation capabilities.

import { motion, AnimatePresence } from 'framer-motion';

function AnimatedList({ items }) {
  return (
    <ul>
      <AnimatePresence>
        {items.map(item => (
          <motion.li key={item.id}
            initial={{ opacity: 0, x: -20 }}
            animate={{ opacity: 1, x: 0 }}
            exit={{ opacity: 0, x: 20 }}
            transition={{ duration: 0.3 }}
          >
            {item.text}
          </motion.li>
        ))}
      </AnimatePresence>
    </ul>
  );
}

Practice Task

Build a product catalog page with a grid layout using Material UI's Grid component. Display at least six product cards, each with an image placeholder, title, price, and an "Add to Cart" button. Use a sortable table view as a toggleable alternative to the grid. Add a Framer Motion animation when items appear or are removed from the view.