Frontend Patterns

Pattern

Presentational vs. Container

Separate components that handle UI rendering from those that manage data and business logic.

Component Beginner

Presentational vs. Container

Problem

Components tightly couple UI rendering with data fetching, state management, and business logic, making them impossible to reuse with different data sources or test independently. Changes to the API or business rules require modifying components that should only care about presentation.

Solution

Separate components that render UI (presentational) from those that fetch data and manage state (container). This makes presentational components reusable and easier to test in isolation.

Example

This example shows separation of concerns: a presentational component that only renders UI, and a container component that handles data fetching and state management.

// Presentational component - only renders UI
// No data fetching, no business logic, just presentation
class UserList extends HTMLElement {
  set users(value) {
    this._users = value;
    this.render();
  }

  render() {
    // Pure rendering based on props
    const items = this._users.map(u => `<li>${u.name}</li>`).join('');
    this.innerHTML = `<ul>${items}</ul>`;
  }
}

// Container component - handles data fetching
// Manages state and passes data to presentational component
class UserListContainer extends HTMLElement {
  async connectedCallback() {
    // Fetch data from API
    const users = await fetchUsers();
    // Pass data down to presentational component
    const userList = this.querySelector('user-list');
    userList.users = users;
  }

  render() {
    this.innerHTML = '<user-list></user-list>';
  }
}

Benefits

  • Makes presentational components reusable across different data sources.
  • Simplifies testing by allowing pure components to be tested without mocks.
  • Creates clear separation between UI rendering and business logic.
  • Enables designers to work on presentational components independently.

Tradeoffs

  • Creates additional layers of components, adding boilerplate.
  • Can be over-engineering for simple components that don’t need reuse.
  • Makes component trees deeper and potentially harder to navigate.
  • Largely superseded by hooks which provide better composition.
Stay Updated

Get New Patterns
in Your Inbox

Join thousands of developers receiving weekly insights on frontend architecture patterns

No spam. Unsubscribe anytime.