Development

Why I Prefer Attribute-Based Styling

4–5 min read

Why I Prefer Attribute-Based Styling

I have spent a lot of time working with different ways of styling interfaces.

Traditional CSS, utility classes, component styles, design systems, and different combinations of all of them each solve real problems.

But I kept coming back to one idea: I wanted the markup to describe the styling intent directly.

That idea eventually became the foundation for my attribute-based styling approach.

The problem I was trying to solve

Consider a normal component with several utility classes:

<div class="bg-blue-500 p-4 grid grid-cols-2 gap-4">
    ...
</div>

There is nothing inherently wrong with this.

Utility classes are powerful, predictable, and widely adopted.

But I personally found myself wanting a different relationship between markup and styling.

I wanted the HTML to read more like a set of properties.

<div bg="blue-500" p="4" grid-cols="2" gap="4">
    ...
</div>

The difference is subtle.

Instead of seeing a list of class names, I see a collection of attributes describing the element.

That is the mental model I wanted to explore.

Attributes communicate intent

HTML attributes already describe characteristics and behavior.

disabled, required, href, type, and aria-label all add meaning to an element.

So the idea of using attributes for styling felt natural to me.

An attribute such as p="4" immediately tells me that the element has a padding value.

Likewise, grid-cols="2" communicates a grid decision.

The goal isn't to claim that this is universally better.

It is simply a different API.

And API design is one of the most interesting parts of building developer tools.

Responsive styles become readable

One area where I particularly like this approach is responsive styling.

For example: grid-cols="1" md-grid-cols="2" lg-grid-cols="4"

The base behavior is visible.

Then the responsive changes are visible beside it.

There is no separate stylesheet to mentally connect with the markup.

Again, this is a preference, not a universal rule.

Different developers have different ideas about what makes markup readable.

But for me, seeing the responsive behavior in the same place as the component is useful.

State variants follow the same idea

The same mental model can extend to interaction states.

For example, a button with bg="blue-500" hover-bg="blue-600" focus-ring="2" describes its normal state and its interaction behavior together.

That makes state design harder to ignore.

A common problem in UI development is remembering the default state while forgetting hover, focus, active, disabled, and other states.

Putting these decisions close to the element encourages thinking about them.

A styling API needs discipline

The biggest danger with any styling system is becoming inconsistent.

If attributes are added randomly, the system becomes difficult to learn.

So a framework like this needs conventions.

Naming needs to be predictable. Values need to follow understandable scales. Variants need consistent syntax. Responsive behavior needs clear rules. Colors and spacing need a coherent token system.

This is where building the framework became much more interesting than the syntax itself.

The syntax is only the surface.

The system underneath is what determines whether the idea actually works.

Less configuration, more convention

One of my goals has always been to keep the initial experience simple.

I don't want a developer to spend an hour configuring a styling framework before writing their first component.

A good default system should handle common needs immediately.

That doesn't mean customization isn't valuable.

It means customization should solve a real problem rather than become a requirement for basic usage.

The interesting part is not replacing CSS

I don't see attribute-based styling as a reason to stop learning or using CSS.

CSS is still the foundation.

The framework is an abstraction on top of it.

That distinction matters.

If you don't understand the underlying platform, abstractions can become frustrating very quickly. But when the abstraction is built on a solid understanding of CSS, it can make repetitive work faster and more consistent.

That is the space I am interested in.

Building the framework changed how I think about APIs

The project taught me that developer experience is really API design.

A developer tool is successful when the user can predict what happens.

The fewer surprises, the better.

If I see an attribute and value combination, I should have a reasonable idea of the result.

If I combine a responsive variant with a base value, the behavior should make sense.

If something isn't supported, the failure should be understandable.

These principles apply to far more than styling.

They apply to libraries, components, backend APIs, and entire products.

Why I keep exploring the idea

The reason I continue to find attribute-based styling interesting isn't because I think every developer should use it.

It is because changing a familiar interface can reveal assumptions we stop noticing.

Sometimes the best way to understand a problem is to redesign the API around it.

That is what this project gave me.

It started as a styling experiment.

It became an exercise in API design, architecture, documentation, developer experience, and product thinking.

And that is much more valuable to me than the syntax alone.