The library that fixed ownership and caused sameness

Harsh Chhajer
4m read

You ask an agent for a component library, it reaches for shadcn, and you get exactly what everyone else asking the same question got: the same rounded card, the same muted grey border, the same default spacing. shadcn didn't fail here. It did precisely what it was built to do, for a different problem than the one you're now noticing.

The problem shadcn actually solved

Before shadcn, a component library meant a package: install it, import from it, and every update to the package is a decision the maintainer made without you. Customizing deeply meant fighting the abstraction the library was built around.

shadcn/ui, now past 122,000 GitHub stars, solved that by refusing to be a package at all. You copy the component's actual code into your own project. There is no dependency to be locked into, because there is no dependency. You own every line from the moment you add it, which is exactly the ownership model a decade of "why does upgrading this library keep breaking our app" complaints was asking for.

The same property that made it copyable is why it looks the same everywhere

That openness has a side effect nobody designed for. Of the visual fingerprints that give away an AI-generated interface this year, shadcn's default styling is one of the two that show up most, alongside glassmorphism. The mechanism is not mysterious. shadcn is structured to be easy to copy and paste, which is precisely what makes it easy for an agent to copy and paste. Asked for a page with no styling direction attached, an agent reaches for the best-documented option available, and that option is the same component set every other agent is reaching for at the same moment.

The library did not become more popular because it looks distinctive. It became ubiquitous because it is easy to copy, and ubiquity plus zero customization is what produces sameness.

Ownership and distinctiveness are two different fixes

It is tempting to read this as shadcn's fault. It isn't. Code ownership and visual distinctiveness solve different problems, and shadcn was only ever built to solve the first one. Owning your component code was never a promise that the component would look like nothing else on the internet.

A library that shipped genuinely distinctive defaults would have made a different trade: harder to theme predictably, easier to spot at a glance, and probably a smaller number attached to its star count, because distinctive defaults are exactly the thing every team ends up ripping out first.

If you're using shadcn, or anything built the same way, the fix is treating the copy-in step as the start of customization, not the finish line, rather than switching libraries.

What to change in the next ten minutes

Open your project's theme file and change three tokens before you generate anything else with it: the border radius, the base accent, and the font stack. Those three carry most of the visual fingerprint, and they are the three nobody touches.

@layer base {
  :root {
    /* 1. Radius. The 0.5rem default is the single loudest shadcn tell.
          Commit to sharp (0rem) or genuinely round (1rem), not the middle. */
    --radius: 0rem;

    /* 2. Accent. Replace with your own hue. Anything in the 250-280
          range is the indigo/violet band every generated UI already sits in. */
    --primary: 12 76% 47%;
    --primary-foreground: 0 0% 100%;

    /* 3. Ring, so focus states stop pointing back at the old accent. */
    --ring: 12 76% 47%;
  }
}
// 4. The font stack, the other half of the fingerprint. Name a real pairing.
theme: {
  extend: {
    fontFamily: {
      sans: ['Söhne', 'Inter', 'system-ui', 'sans-serif'],
      serif: ['Spectral', 'Georgia', 'serif']
    }
  }
}

That is a ten-minute edit, and it is the difference between a page that's obviously running the defaults and one that happens to be built on the same solid foundation as everyone else's, without looking like it.