DEV Community

Cover image for I Got Tired of Class-Heavy UI Code — So I Kept Going (Juice Part 3)
Drew Marshall
Drew Marshall

Posted on

I Got Tired of Class-Heavy UI Code — So I Kept Going (Juice Part 3)

In Part 1, I talked about the frustration.

In Part 2, I showed the direction.

Now in Part 3, we’re going deeper into what Juice is actually becoming.

Because at this point…

This isn’t just about styling anymore.


The Real Problem Was Never Classes

Classes were just the symptom.

The real problem?

We’ve been writing UI in a way that separates what something is from how it behaves.

<div class="flex items-center justify-between p-4 bg-gray-900 text-white rounded-lg shadow-md">
</div>
Enter fullscreen mode Exit fullscreen mode

This doesn’t describe intent.

It describes implementation.


Juice Is About Intent

With Juice, I’m not trying to replace Tailwind.

I’m trying to replace how we think about UI.

<div layout="row space-between center" padding="4" surface="dark" text="white" radius="lg" elevation="md">
</div>
Enter fullscreen mode Exit fullscreen mode

Now we’re talking.

  • layout → structure
  • padding → spacing
  • surface → semantic background
  • text → semantic color
  • radius → shape
  • elevation → depth

This is no longer a pile of utilities.

This is a language.


From Styling → System Design

Here’s the shift that changed everything for me:

Juice isn’t a CSS library. It’s a UI protocol.

That means:

  • Defined attributes
  • Predictable behavior
  • Shared contracts across components
  • Extensible rules

Sound familiar?

That’s because it mirrors how we already think about:

  • APIs
  • Schemas
  • Infrastructure

So why doesn’t UI get the same treatment?


The Missing Layer in Frontend

We have:

  • Frameworks (React, Vue, etc.)
  • Styling systems (Tailwind, CSS Modules)
  • Component libraries (MUI, Chakra)

But we don’t have a standardized way to describe UI itself.

Juice is aiming to sit right there:

[ App Logic ]
      ↓
[ UI Description Layer (Juice) ]
      ↓
[ Render Layer (DOM / Canvas / WebGL) ]
Enter fullscreen mode Exit fullscreen mode

That middle layer?

That’s the gap.


Attributes > Classes Isn’t the Point

Let’s be clear:

This isn’t about:

“attributes are better than classes”

That’s shallow.

The real win is:

Attributes let you define rules and contracts more naturally.

Example:

<button variant="primary" size="lg" state="loading">
</button>
Enter fullscreen mode Exit fullscreen mode

Now imagine:

  • variant ties into your design system
  • size scales consistently everywhere
  • state drives behavior + visuals

This becomes a shared interface, not just styling.


Composability Without Chaos

One of the biggest issues with utility-first systems:

They scale visually but not conceptually.

You end up with:

<div class="flex gap-2 p-3 sm:p-4 md:p-6 bg-neutral-800 hover:bg-neutral-700 transition-all duration-200">
</div>
Enter fullscreen mode Exit fullscreen mode

Multiply that across an app…

Now try to refactor it.

Good luck.

With Juice:

<div layout="row gap-2" padding="responsive" surface="neutral-800" interaction="hover-surface" transition="fast">
</div>
Enter fullscreen mode Exit fullscreen mode

Now:

  • Behavior is abstracted
  • Patterns are reusable
  • Refactoring becomes changing rules, not hunting classes

This Is Where It Gets Interesting

Once UI becomes declarative like this…

You unlock things like:

1. Theming at a System Level

<app theme="corporate-dark">
</app>
Enter fullscreen mode Exit fullscreen mode

Everything adapts.

No class overrides.
No specificity wars.


2. Dynamic UI Generation

Now your UI can be generated from:

  • JSON
  • YAML
  • APIs
  • AI (👀)

Because it's structured.


3. Cross-Platform Rendering

Same UI definition could target:

  • DOM
  • Canvas
  • WebGL
  • Native

Because Juice isn’t tied to one renderer.


Juice + The Bigger Picture

This is where Juice connects to everything else I’m building.

  • Sig → rendering & reactivity
  • Nectarine → data & APIs
  • Seltzer → HTTP layer
  • GrapeVine → infrastructure

Juice becomes:

The way UI is defined across the entire system.

Not just styled.


Where This Is Going

Right now, Juice is still evolving.

I’m documenting rules.
Defining protocols.
Figuring out where flexibility ends and standards begin.

But the direction is clear:

UI should be declarative, structured, and system-driven.

Not just styled with strings.


Final Thought

I didn’t start building Juice because I hated CSS.

I started building it because I realized:

We’ve been missing a layer.

And once you see it…

You can’t unsee it.


Part 4 is where things start getting real.

We’ll talk about:

  • Rules & constraints
  • How Juice avoids becoming chaos
  • And how this turns into an actual engine

Stay tuned.

Top comments (0)