When should I use presentational components? What if I want the benefits of purely visual components without having to separate presentation from logic?
Separation of presentation from logic has been an ongoing pursuit throughout the history of front-end development. Why? We are trained as engineers to separate concerns. If the UI is isolated, then business logic can change without requiring a UI update (and vice versa).
The Prehistory of Presentational Components
Before the advent of React, Model-View-Controller (MVC) frameworks structured websites with presentational “views” separated from the “controllers” which managed application and logic and “models” which managed data.
While devs could easily isolate models, the isolation of presentation into views proved difficult. Despite limited success with templates in MVC frameworks, purely presentational views didn’t scale. Codebases on big apps inevitably ended up with “view controllers” specifying both logic and layout.
Presentational Components in React
As React and similar frameworks grew to prominence, again the promise of separating presentation from logic tempted the front-end community. This time around the leading approach was “purely presentational components”, whose behavior is determined solely on props they received. Such components have internal state, but are unaware of the rest of the system.
Design Systems and Presentational Components
The presentational component approach works well with low-level components: buttons, labels, dropdowns, etc. These “atoms” don’t depend on external state and thus their presentation is independent of (most) other system considerations. Over time, this led to collections of such components which we now know as “design systems.”
The great variety of low-level component libraries (MUI, Chakra UI, Mantine, ThemeUI, Ant Design) speaks to the success of this approach. Teams also build their own internal design systems, with presentational components. Design system managers allow non-engineers to manage and use these components. A new generation of design tools with “code components” (Plasmic, UXPin, Clutch, Builder.io) allow designers to bring presentational components into their designs to enhance the fidelity of prototypes.
The design systems approach reveals the limitations of presentational components. While some system-side variables (such as themes) are honored, components that depend more richly on application state can’t be easily supported. At best, a complex rig or fixture is set up to mimic application state. As the application evolves, this rig must be maintained. Design systems end up supporting only a fraction of the application.
Complexity and Presentational Components
If you look at a typical production React repo, you’ll see one of two scenarios:
- For projects that don’t use an external design system, < 10% of the components are presentational
- For projects that do use an external design system, even fewer of the components are presentational because an external repo (e.g https://github.com/mui/material-ui) provides low-level UI building blocks.
The limitation is the same fundamental limit we saw with MVC. The presentational approach doesn’t scale to complex interactions, and UIs are getting more sophisticated with each passing year. Many React devs have valiantly attempted to maintain the presentational separation with paired components (e.g. a PurchasePageController
to handle the logic of the purely presentational PurchasePageView
) and failed. The complexity is too much to bear.
Front-end developers deserve a better way to separate UI/UX concerns as they build web apps without having to write awkward code or otherwise be bogged down. Fortunately, the industry is finding new ways to streamline development.
Separation of Presentation and Logic Through Tooling
The latest front-end devtools work on the presentational aspects of complex components that are connected to application state.
An important pioneer in this direction is Storybook which visualizes the components in a React codebase based on a collection of developer-created fixtures called stories. Developers can test, manage, and share components with team members. While Storybook most naturally supports purely presentational components, arbitrarily complex components can be supported with the proper fixtures.
Storybook is powerful for visualization, but doesn’t allow editing the components, and creating/maintaining stories is time consuming especially for complex components.
A new generation of products is emerging that allow the visual UI to be changed for complex components, without affecting the logical function. One of these tools is Codux, from Wix. Codux is like Storybook with editing. Devs can work on the visual aspects of components without considering logic (once the fixtures have been set up).
Another such tool is MightyMeld, which opens up your whole app for visual editing. Since MightyMeld runs on top of a live running app, it doesn’t need fixtures. Data is provided by the regularly running app, and components of any level of complexity can be worked on in-context with no need for fixture creation or maintenance . Unlike Storybook and Codux, MightyMeld deals with the important use case of components that richly interact with application state for which no reasonable fixtures can be written and maintained.
The Future of Presentation, Separate from Logic
We're seeing a promising new direction emerge for front-end development: tools that provide a workflow that separates UI from logic without affecting code. No more having to compromise on DevEx to keep your code clean.
We are tantalizingly close to the holy grail of separation of presentation and logic: the development of UI, not just by engineers, but by designers, product managers, and others on the team. Look and feel is often driven by team members that can’t hack through a serious codebase. Tools that make developer’s lives easier also make apps (and code) more accessible to the rest of the team.
It seems our long quest to separate presentation from logic is finally reaching a victorious conclusion.