English · 00:32:11 Jan 21, 2026 8:13 AM
UI, Pure and Simple (by Christian Johansen)
SUMMARY
Christian Johansen delivers a talk on Replicant, a pure Clojure UI library enabling stateless, functional rendering with immutable data, demonstrated through a Combon board app to simplify frontend development.
STATEMENTS
- React launched in 2013 with the concept that UI is a pure function of application state, rendering from scratch each time while the framework optimizes updates.
- Quiescent refined React's model by enforcing top-down rendering where components lack internal state and do not self-rerender, emphasizing UI as solely dependent on global application state.
- Replicant is a lightweight ClojureScript virtual DOM library designed for pure functions and immutable data, avoiding dependencies and built-in state management.
- Rendering in Replicant uses Hiccup to convert domain data into UI structures, which are then diffed and applied minimally to the DOM for efficiency.
- Application state can be managed via a Clojure atom or Datascript database, with watchers triggering rerenders on changes to maintain a unidirectional data flow.
- Event handling in Replicant uses data descriptors instead of functions, dispatched globally to keep rendering pure while centralizing side effects.
- Actions are structured as keyword-named tuples with attributes, processed in a dedicated handler to ensure predictability and explicit side effects.
- Testing UI involves generating Hiccup from sample data and using selectors like those in the Lookup library to assert on behavior without design fragility.
- Animations and transitions are declarative: CSS keyframes for simple effects, unmounting attributes for fade-outs, and timed delays via state markers and setTimeout.
- Aliases allow imperative code in data form as custom keywords bound to functions, enabling higher abstractions like autofocus or third-party integrations without polluting purity.
- Forms and inputs handle dynamic values through placeholders resolved post-event via a walk function, serializing data for submission while staying data-driven.
- Backend integration treats APIs as external dispatchers updating the central store, allowing the render loop to react to loading, success, or error states without coupling.
IDEAS
- React's promise of pure UI functions was undermined by pervasive mutable state, leading to complexity that ClojureScript tools like Quiescent aimed to curb through strict top-down constraints.
- Replicant's event system turns handlers into pure data, enabling custom architectures like re-frame or Elm without embedding functions in views, preserving determinism.
- Visual testing in Portfolio treats entire UI states as static scenes from domain data, decoupling design iteration from runtime behavior for faster prototyping.
- Impurity spreads contagiously in code, but centralizing mutations in a single action handler isolates side effects, making large codebases more predictable and scalable.
- Hiccup selectors mimic CSS for querying rendered structures, allowing focused unit tests on behavior that run on JVM without browsers, ideal for hundreds of checks.
- Declarative unmounting attributes trigger CSS transitions before DOM removal, simplifying common animations without asynchronous hooks or lifecycle complexity.
- Placeholders in action data resolve to event values like input text or form serialization at dispatch time, bridging render-time limitations with runtime realities purely.
- Aliases encapsulate imperative operations as data keywords, raising abstraction in Hiccup for tests that reason about concepts like "fire icon" instead of SVG paths.
- The central store as single source of truth integrates APIs, routing, and subscriptions seamlessly, keeping 80-90% of frontend code domain-focused and loosely coupled.
- Live multi-user demos via service events highlight how data-agnostic rendering adapts effortlessly to streaming updates, changing only the bootstrap action.
- Pure UIs enable static reproduction of all user-facing states in tools like Portfolio, honing designs in isolation while ensuring reproducibility for debugging.
- Replicant's minimalism rejects complexity by enforcing unidirectional flow, making development productive and enjoyable through simplicity and explicitness.
INSIGHTS
- Embracing immutable data and pure functions in UI rendering fundamentally decouples visuals from logic, fostering modular, testable code that scales without entanglement.
- Centralizing side effects in explicit action handlers transforms potential chaos into controlled predictability, echoing functional programming's emphasis on composition over mutation.
- Data-driven events and placeholders elegantly resolve timing mismatches between rendering and interaction, maintaining purity while handling real-world dynamism.
- Higher abstractions via aliases and selectors shift testing from brittle details to conceptual behaviors, aligning verification with intended outcomes rather than implementation quirks.
- Treating the application state as the universal integration point insulates core UI logic from external systems, promoting loose coupling and effortless adaptability to new data sources.
- Pure UI paradigms not only simplify development but enhance joy in building, as reproducible states and minimal infrastructure reduce cognitive load and amplify creativity.
QUOTES
- "Can UI code really be pure and simple? That's what I want to explore in this talk."
- "Impurities is really contagious. Just a single drop and everything is destroyed."
- "The UI literally is a pure function of application state."
- "All it cares about is data. And this ensures that your app really stays very loosely coupled."
- "It's productive and really fun way to work."
HABITS
- Maintain a blog to share insights with colleagues, focusing on practical Clojure experiences.
- Give frequent conference talks to disseminate knowledge on web technologies and functional UI.
- Contribute to open-source libraries in the Clojure ecosystem, including maintenance of tools like Replicant.
- Use top-down rendering constraints in all projects to enforce stateless components and global state dependency.
- Isolate component variations in visual suites like Portfolio for iterative design without full app runtime.
FACTS
- React was introduced in 2013, revolutionizing UI thinking by modeling it as a function of state but allowing mutable components.
- Quiescent, by Luke Vandermost, popularized top-down rendering in ClojureScript by prohibiting component-local state.
- Christian Johansen has 20 years of software development experience, with the last 10 fully in Clojure at the Norwegian Food Safety Authority.
- Replicant supports CSS-like selectors via the Lookup library for hiccup querying, enabling JVM-based UI tests.
- Combon boards enforce work-in-progress limits, such as two cards maximum in a column, to optimize team flow.
REFERENCES
- Replicant: ClojureScript virtual DOM library for pure rendering.
- Quiescent: ClojureScript React wrapper enforcing top-down rendering.
- Hiccup: Library for representing HTML as Clojure data structures.
- Portfolio: Tool like Storybook for ClojureScript, rendering UI scenes.
- Lookup: Library for CSS-selector queries on Hiccup data.
- Datascript: In-memory database for application state management.
HOW TO APPLY
- Define application state as an immutable snapshot in a Clojure atom, naming the atom "store" and snapshots "state" for clarity in state evolution over time.
- Create pure rendering functions that thread state through nested components, converting domain data to Hiccup for declarative UI description.
- Set up a watcher on the store to invoke the top-level render function on changes, passing Hiccup to Replicant's DOM render for efficient updates.
- Structure event handlers as data tuples with keywords for side effects, registering a global dispatch via set-dispatch to process actions centrally.
- Implement timed effects by scheduling future state updates with setTimeout in action handlers, triggering renders for auto-disappearing elements like toasts.
ONE-SENTENCE TAKEAWAY
Pure functional UIs with immutable data simplify development, enhance testability, and boost productivity in ClojureScript applications.
RECOMMENDATIONS
- Adopt top-down rendering to eliminate component state, ensuring UI purity and easier debugging across the application.
- Centralize all mutations in a single action handler using data descriptors, reducing global mutable state risks.
- Use visual tools like Portfolio to prototype full app states statically, accelerating design feedback loops.
- Integrate placeholders for runtime values in events, enabling data-driven forms without compromising render purity.
- Leverage a central store for all integrations, keeping core UI logic agnostic to APIs or subscriptions for modular scalability.
MEMO
In the evolving landscape of frontend development, where mutable state often breeds complexity, Christian Johansen offers a refreshing antidote through Replicant, his minimalist ClojureScript library. Presented at reClojure 2025, Johansen's talk, "UI, Pure and Simple," argues that user interfaces can thrive on immutable data and pure functions alone. Drawing from React's 2013 breakthrough—that UI is merely a function of application state—Johansen critiques how it devolved into state sprawl. Instead, he champions tools like Quiescent's top-down rendering, where components remain stateless, rerendering solely from global updates. With Replicant, Johansen demonstrates this philosophy via a Combon board app, rendering tasks, columns, and interactions as declarative Hiccup data structures fed into a virtual DOM.
Johansen's demo unveils a stripped-down yet powerful workflow. State resides in a simple Clojure atom, watched for changes that trigger efficient DOM diffs. Events bypass imperative callbacks, opting for data payloads dispatched globally—keywords naming side effects like toggling expansions or submitting forms. This keeps rendering pure: no functions lurking in views, just immutable snapshots yielding predictable outputs. For dynamism, Johansen introduces clever hacks: placeholders resolve input values post-event, aliases encapsulate imperative needs like autofocus as data keywords, and unmounting attributes orchestrate CSS transitions for fading toasts. Animations emerge not from hooks but from state markers and setTimeout, ensuring even timed effects stay declarative.
Testing, often a pain in interactive UIs, becomes trivial here. Johansen's Lookup library applies CSS-like selectors to Hiccup, letting developers assert on behaviors—like a toggle button's action—without fragile positional queries or browser dependencies. These unit tests run on the JVM, scalable to hundreds. Visual validation shifts to Portfolio, akin to Storybook, where domain data generates isolated scenes of cards in various states: tagged, expanded, or erroneous. This data-centric isolation decouples design tweaks from logic, fostering rapid iteration. Johansen notes the contagion of impurity—one mutable drop ruins purity—but his model quarantines it, centralizing mutations for predictability as codebases grow.
Beyond basics, Johansen integrates real-world demands seamlessly. APIs initiate via dispatched queries, updating the store to signal loading or errors, which the renderer queries declaratively. Routing or subscriptions follow suit, treating the store as the single truth. A live demo swaps static data for server streams, enabling multi-user drags across browsers with minimal code changes—one bootstrap line. This loose coupling ensures 80-90% of frontend code handles pure domain-to-UI transforms, oblivious to backends. Johansen, with two decades in software and a decade in Clojure at Norway's Food Safety Authority, credits collaborators for these insights, honed through open-source maintenance and conference talks.
Ultimately, Johansen's vision proves UIs can be not just functional but joyful. Replicant's no-frills approach rejects bloat, yielding apps that are testable, reproducible, and fun to build. Static Portfolio renders capture every conceivable screen state, from empty loads to failure modes, while dev tools like Datascript browse the store interactively. In an era of framework fatigue, this pure path—unidirectional flow, explicit effects, data everywhere—invites developers to rediscover simplicity. For Clojurians, Johansen urges joining the Replicant Slack channel; for all, his tutorials beckon toward cleaner code. As applause fades, the message lingers: purity isn't sacrifice—it's liberation.
Like this? Create a free account to export to PDF and ePub, and send to Kindle.
Create a free account