Unstyled Components: A Must for Modern Web Applications

Web development has evolved dramatically over the past decade.

Not long ago, developers’ biggest challenges were ensuring cross-browser compatibility, optimizing every kilobyte to load on slow connections, and working around the limits of CSS 2.1 and XHTML 1.0. (Who hasn’t used an image just to create a rounded corner back when border-radius didn’t exist? 😅)

Today, the landscape is completely different. Frameworks and libraries offer ready-to-use solutions that speed up delivery and simplify workflows. Yet, with this convenience comes new complexity: building truly accessible, scalable, and user-friendly applications now demands careful attention to every component.

That’s where libraries like Bootstrap and Material UI became game-changers. Suddenly, developers could create forms, dropdowns, and even entire pages simply by combining pre-built components. But this came at a cost: as these tools applied the same default styles (even down to micro-interactions), countless applications started to look identical. Visual identity often took a back seat, leaving brands struggling to stand out.

A new era: unstyled components

While libraries like Bootstrap and Material offered theme customization options, integrating them seamlessly into a proprietary design system was far from straightforward.

As interface design evolved, so did the demand for greater flexibility and visual consistency. That’s exactly where unstyled components come into play.

The concept behind unstyled components is both simple and powerful: they deliver pre-built, accessibility-compliant components, tested across multiple use cases and equipped with a solid, native API, while remaining fully extensible for custom scenarios.

This shifts the developer’s focus toward what truly matters: the product’s visual identity. Each component can be adapted to match the application’s design system without sacrificing usability or scalability.

Let’s break down how this approach redefines front-end development.

Accessibility

Building accessible components from scratch is no simple task. It requires correctly applying WAI-ARIA attributes, ensuring full keyboard navigation, supporting screen readers, and following established usability best practices, all while maintaining a seamless experience.

Unstyled components take care of that groundwork. They come pre-tested for accessibility, greatly reducing the likelihood of inclusion or compliance issues. This allows developers to focus on visual customization while keeping a solid, inclusive foundation that meets modern accessibility standards.

How To Build An App: Best Practices for Developing Scalable Apps

Bulletproof

Unstyled components are thoroughly tested in different scenarios, including unit and integration tests, ensuring reliable performance in real-world situations.When you adopt them, you gain a solid, well-structured foundation and a consistent user experience from day one.

The component logic is already validated, so your team can concentrate on customizing the look and aligning it with your design system, without sacrificing usability or consistency.

Flexible API

Another important aspect is flexibility. Unstyled components provide an open API that allows teams to compose and extend behaviors while keeping the original structure intact. This is where the Compound Pattern stands out, serving as a key principle in component-driven user interfaces built with React. 

Even the simplest elements, like buttons, can have many variations such as custom icons, different icon positions, or multiple states. When these variations are managed directly through props, the code can easily become cluttered and harder to maintain.

The Compound Pattern helps organize each subcomponent in a modular and composable way, keeping the main component’s API clean, predictable, and scalable. This approach creates a flexible and reusable architecture that maintains consistency and adaptability across the entire interface.

Component controlled via props: 

type ButtonProps = {
  label: string;
  icon?: React.ReactNode;
  iconPosition?: "left" | "right";
};

export const Button: React.FC<ButtonProps> = ({ label, icon, iconPosition = "left" }) => {
  return (
    <button className="flex items-center gap-2 px-4 py-2 border rounded">
      {icon && iconPosition === "left" && <span>{icon}</span>}
      {label}
      {icon && iconPosition === "right" && <span>{icon}</span>}
    </button>
  );
};

// Using
<Button label="Save" icon="💾" iconPosition="left" />
<Button label="Delete" icon="❌" iconPosition="right" />

Same component using the Compound Pattern:

export const Button: React.FC<{ children: React.ReactNode }> & {
  Icon: React.FC<{ children: React.ReactNode; position?: "left" | "right" }>;
  Label: React.FC<{ children: React.ReactNode }>;
} = ({ children }) => {
  return <button className="flex items-center gap-2 px-4 py-2 border rounded">{children}</button>;
};

Button.Icon = ({ children }) => (
  <span>{children}</span>
);

Button.Label = ({ children }) => <span>{children}</span>;

// Using
<Button>
  <Button.Icon>💾</Button.Icon>
  <Button.Label>Save</Button.Label>
</Button>

<Button>
  <Button.Label>Delete</Button.Label>
  <Button.Icon></Button.Icon>
</Button>
Code language: JavaScript (javascript)

From unstyled to styled components

One of the greatest advantages of unstyled components is the complete control they provide over styling. You can apply Tailwind, CSS Modules, native CSS, or any other preferred approach that fits your stack and workflow.

This flexibility makes it easy to connect your application’s design system, adjust themes, or create visual variations without changing the component logic. The clear separation between logic and style, known as the container/presentational pattern, keeps the visual identity consistent across the interface while ensuring components remain accessible, validated, and ready for production use.

At this point, developers can focus on delivering real value to the project by creating accessible interfaces with excellent usability and visual consistency that align closely with the design system. This approach helps each application maintain its unique character instead of looking identical, as many did during the Bootstrap era.

It also allows teams to spend less time on repetitive visual details and more on crafting microinteractions that bring the interface to life, creating a smooth, enjoyable, and well-designed user experience.

Interface Builder: Pros, Cons and Our Thoughts

Stop there? Not quite.

Everything discussed here comes from Cheesecake Labs’ experience with Radix UI, but there are other well-known unstyled component libraries, such as Headless UI and Base UI, the latter created by the same developers behind Radix and Material. These teams have deep expertise in building robust, scalable UI foundations.

A recent and increasingly popular extension of Radix in the web development community is shadcn/ui. Instead of following the usual workflow of installing via npm, importing a component, and using it right away, shadcn/ui embraces a more hands-on approach built for projects that demand real flexibility. It addresses common challenges like adapting components to a design system or managing incompatible

APIs across libraries, and it offers:

  • Open source structure: the top layer of each component can be fully customized.
  • Composable architecture: all components share a consistent and predictable interface.
  • Efficient distribution: simple file organization and CLI tools for easy component sharing.
  • AI-ready foundation: open code that LLMs can read, interpret, and enhance.

In the end, unstyled components combined with tools such as shadcn/ui make it possible to create interfaces that are accessible, scalable, and visually consistent, while allowing developers to focus on microinteractions and thoughtful details that make user experiences truly memorable.

At Cheesecake Labs, these principles are applied in real projects to deliver products that balance functionality, strong design identity, and seamless usability, showing that investing in component-driven development leads to smarter, more engaging, and future-ready digital experiences.

About the author.

Jonathan Felipe de Oliveira
Jonathan Felipe de Oliveira

I love helping people using creative solutions, from design to code. Also I love art, music, outdoors and travel. Pet and Plant father 🥸