DEV Community

Karmello
Karmello

Posted on • Originally published at nebulakit.dev

Design Systems and the Problem of UI Entropy

UI entropy is inevitable

Frontend projects don't fail suddenly, they decay gradually. Well-defined conventions inside a project are usually not enough to stop it. Copy-paste, exceptions, overrides and "just this once" decisions accumulate. Entropy increases unless something actively resists it. UI libraries exist to slow it down, but most of them don't do as much as they could to limit its impact. If you've ever looked at a mature codebase and thought "how did we end up here?" - you've seen UI entropy in action.

The rest of this article describes crucial aspects of a UI library that, when designed with care, can decrease UI entropy in the consuming application.

1. Props API

Problem

The UI library does not use consistent naming for props that control the same behavior across different components.

Consequence

  • you keep seeing different props that perform the same underlying job
  • that inconsistency makes it harder to reason about a component's internal structure

Root cause

  • composition is likely breaking down
  • props that do the same thing are not inherited but are created separately for each component

Alternative approach

  • if a prop can be inherited, it should always be inherited
  • inherited props should never be renamed, so if a component is composed of Flex under the hood and exposes its flexDirection prop, it should reuse the same name
  • this way, the props API teaches about the composition used internally

2. HTML semantics

Problem

The UI library does not enforce semantic HTML structure.

Consequence

  • semantic meaning is being lost over time
  • accessibility regressions appear
  • linters, static analysis and code reviews can't reliably detect semantic breakage, especially when the markup remains technically valid
  • developers need to actively think about semantic correctness

Root cause

  • UI library components render generic HTML tags by default
  • using semantic HTML tags is optional

Alternative approach

  • the UI library should encode semantic meaning into the component contract
  • the root HTML tag should be fixed in case variation is harmful
  • only valid HTML tag alternatives should be exposed when flexibility is required
  • this way, incorrect structures become impossible to express

3. Styling system

Problem

The UI library does not keep styling concerns clearly separated.

Consequence

  • setting a value for a single styling axis (variant or intent) impacts multiple axes at the same time

Root cause

  • styling system axes are entangled
  • there is no clear separation between variant and intent
  • visual decisions are not clearly separated at the CSS level

Alternative approach

  • styling should be modeled as orthogonal axes
  • each axis should answer one question only
  • there should be no implicit coupling between variant and intent
  • this way, visual combinations are always predictable

4. Responsiveness mechanism

Problem

The UI library does not enforce a consistent responsive model.

Consequence

  • layout rules behave inconsistently
  • the UI breaks only at certain breakpoints
  • layout behavior changes unexpectedly as screens evolve
  • fixes for one breakpoint regress another
  • developers stop reasoning about layout and start guessing

Root cause

  • responsive behavior is implicit and does not follow a single system model
  • breakpoint rules differ per component
  • multiple independent styles are applied
  • styles are overridden without it being obvious where or why

Alternative approach

  • all components should follow the same breakpoint resolution model, so responsive behavior is consistent across the library
  • responsive rules should be applied from small screens upward, so styles defined for smaller screens continue to apply unless explicitly changed
  • responsive behavior should change only through explicit breakpoint value overrides, never by implicitly "resetting" earlier breakpoint value
  • this way, layout behavior remains predictable as screens and features evolve, instead of changing implicitly over time

5. Composition

Problem

The UI library does not always enforce reuse of shared behavior across components.

Consequence

  • bugs fixed in one place reappear elsewhere
  • refactors are risky because behavior isn't centralized
  • similar components behave slightly differently in edge cases
  • changes require touching multiple components to stay consistent
  • confidence in shared behavior erodes over time

Root cause

  • components are built as isolated units
  • similar components subtly diverge
  • shared behavior is re-implemented instead of reused
  • the same logic exists in multiple places
  • composition stops at convenience boundaries

Alternative approach

  • a component's internal behavior should be encapsulated once
  • higher-level components should compose behavior, never re-implement it
  • there should be no duplicated functionality existing at the component level
  • this way, every behavior would have a single source of truth

6. Configuration

Problem

The UI library allows too much customization at the global level.

Consequence

  • theme configuration objects grow large and hard to reason about
  • endless customization feels like doing work the UI library should keep closed and invisible to the library consumer
  • global decisions leak into local component concerns

Root cause

  • theming is treated as an engine rather than a boundary
  • customization is unlimited and lacks clear scope

Alternative approach

  • global theme and brand should be provided as contextual boundaries
  • local overrides should be explicit and scoped
  • variant and intent should both be handled at the component level
  • isolated styling "islands" should be supported without global side effects

7. Context switching

Problem

The UI library forces developers to keep switching mental context while working on the UI.

Consequence

  • developers constantly switch between JSX and CSS
  • code reviews and debugging become harder and slower
  • "where is this coming from?" moments keep occurring frequently
  • developers juggle multiple mental models to understand a single component

Root cause

  • CSS is treated as a parallel API to the component system
  • styling lives outside component composition
  • styling escapes JSX into unstructured class names, overrides or stylesheets
  • visual logic is detached from structural composition

Alternative approach

  • visual control should stay inside JSX
  • styling props should all map 1-to-1 to CSS properties
  • a single mental model should govern both structure and styling
  • CSS should be a hidden implementation detail, not a developer-facing workflow

Resisting entropy is a system choice

Entropy is not a bug, it's a law. No UI system can eliminate it completely. The difference between systems is how clearly they shape it and how well they slow it down as projects grow. UI library constraints are not limitations, they introduce structure and clarity. Systems that hold up over time are the ones where those constraints are built in, not just documented or expected.

NebulaKit as a response to UI entropy

I started working on NebulaKit as a direct response to the UI entropy patterns described in this article.

The goal was to create a library that treats these problems as system-level constraints, not matters of convention, documentation or discipline. In NebulaKit, these rules are enforced by the component architecture itself, not left to best practices or team agreements. Semantic correctness is part of the component contract. Responsive behavior follows a single explicit model. Shared behavior is composed instead of duplicated. Component APIs reflect how things are built. Styling concerns are separated and scoped so they do not interfere with each other.

The intent is to let frontend projects grow over time, add more features and involve more developers without relying on everyone remembering rules or enforcing them manually.

This article explains why these constraints are important.

The documentation shows how they're enforced in practice.
https://nebulakit.dev

Top comments (0)