Web Components architecture leverages browser-native APIs and web standards to build modular, reusable UI
components without framework dependencies. This approach relies on Custom Elements, Shadow DOM, and ES
Modules to create maintainable web applications with minimal tooling and zero transpilation.
The BCE pattern naturally fits Web Components: Custom Elements act as Boundaries exposing UI interactions,
Controls implement business logic and orchestration using plain JavaScript, and Entities manage
application state through reducers and data models. This results in a clean, standards-based architecture
with unidirectional data flow.
Business Components
Each Web Component represents a cohesive business feature organized in a BCE structure. Components
are named after their domain responsibilities (e.g., product-list, checkout-form, user-profile).
The directory structure follows:
[component-name]/[boundary|control|entity], where boundary contains Custom Element
definitions, control holds business logic, and entity manages state. This ensures
clear separation of concerns and maintainable, reusable UI components.
Boundary
Custom Elements serving as the UI layer and entry point for user interactions. Boundaries render HTML,
handle events, and delegate business logic to control classes. They remain thin, focusing solely on
presentation and event handling without business logic.
Purpose: Render UI and handle user interactions
Directory: [component].boundary
Implementation: Custom Elements extending HTMLElement
Naming: Kebab-case tag names (e.g., product-list, add-bookmark)
Responsibility: DOM manipulation, event handling, template rendering
Architecture Role: UI presentation layer - the only user-facing components
Quantity: One Custom Element per distinct UI component
Thin Design: No business logic - only UI concerns
Access Pattern: User interactions → Event handlers → Control delegation → Re-render
State Management: Subscribe to store changes, dispatch actions
Shadow DOM: Optional encapsulation for styling isolation
Template Engine: lit-html for declarative rendering
Data Flow: User input → Dispatch action → Control processes → State updates → Re-render
Control
Business logic and orchestration layer implementing application behavior as pure JavaScript functions.
Controls handle validation, transformation, API calls, and coordinate state changes through action
dispatching. They remain framework-agnostic and easily testable.
Purpose: Implement business logic and orchestrate operations
Directory: [component].control
Implementation: Plain JavaScript modules with exported functions or classes
Structure: Named after operations (e.g., CRUDControl.js, ValidationControl.js)
Responsibility: Business rules, API integration, data transformation, action dispatching
Architecture Role: Orchestration layer between UI and state
Access Pattern: Called by boundaries, dispatches actions to store
Stateless Design: No instance state - operates on passed parameters
Reusability: Can be invoked from multiple boundaries
Business Focus: Domain-specific operations and workflows
Testability: Pure functions easily unit tested without DOM
Complexity Reduction: Extracts logic from boundaries for maintainability
Coordination Role: Orchestrates API calls, validation, and state updates
Framework Independence: No web component or framework dependencies
Entity
State management layer representing application data and domain models. Entities define the data structure,
reducers handle state transformations, and the store maintains the single source of truth. This layer
ensures predictable state updates through immutable operations.
Purpose: Manage application state and data models
Directory: [component].entity
Implementation: Redux reducers, action creators, and selectors
Structure: Named after domain concepts (e.g., BookmarksReducer.js, UserState.js)
Responsibility: State shape definition, state transitions, data persistence
Architecture Role: Data layer with immutable state management
Business Focus: Domain model representation
Persistence Options: localStorage, IndexedDB, or API synchronization
Access Pattern: Updated via dispatched actions, read via store subscription
Domain Modeling: Define data structures matching business concepts
Immutability: State changes create new objects, never mutate existing
Redux Toolkit: Use createSlice() for reducers and actions
Unidirectional Flow: Actions → Reducers → New State → UI Update
Optional Nature: Can use simple variables for trivial state
Domain Representation: Models real-world business entities and relationships
Implementation Characteristics
Web Standards & Browser APIs
Custom Elements: Define new HTML tags with custom behavior
Shadow DOM: Optional style and markup encapsulation
ES Modules: Native JavaScript module system
Template Elements: Reusable HTML templates with <template>
lit-html: Efficient HTML templating using tagged template literals
No Transpilation: Modern browsers run code directly
localStorage API: Client-side state persistence
Fetch API: Modern HTTP client for API calls
State Management
Redux Toolkit: Simplified Redux for predictable state management
Unidirectional Flow: Actions → Reducers → Store → Components
Single Source of Truth: Centralized application state
Immutable Updates: State changes create new objects
DevTools Integration: Redux DevTools for debugging
Middleware Support: Async operations and side effects
Development Experience
Minimal Tooling: No complex build pipelines required
Fast Refresh: Instant browser updates during development