<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mohammed Fareedh</title>
    <description>The latest articles on DEV Community by Mohammed Fareedh (@itsfareedh).</description>
    <link>https://dev.to/itsfareedh</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F821670%2F9913556b-79b8-4b22-8625-1a182ca6b2aa.jpg</url>
      <title>DEV Community: Mohammed Fareedh</title>
      <link>https://dev.to/itsfareedh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/itsfareedh"/>
    <language>en</language>
    <item>
      <title>Build Clean and Customizable Interfaces with Shadcn UI in React + TypeScript</title>
      <dc:creator>Mohammed Fareedh</dc:creator>
      <pubDate>Fri, 13 Jun 2025 16:46:44 +0000</pubDate>
      <link>https://dev.to/itsfareedh/build-clean-and-customizable-interfaces-with-shadcn-ui-in-react-typescript-4kkh</link>
      <guid>https://dev.to/itsfareedh/build-clean-and-customizable-interfaces-with-shadcn-ui-in-react-typescript-4kkh</guid>
      <description>&lt;p&gt;When building modern front-end applications, developers often struggle to strike the perfect balance between accessibility, design flexibility, and developer experience. Shadcn UI offers a unique solution — combining the power of Radix UI primitives with Tailwind CSS in a developer-friendly and fully customizable package.&lt;/p&gt;

&lt;p&gt;In this post, we’ll explore why Shadcn UI is gaining traction and walk through a step-by-step guide to set it up in a React + TypeScript project. We’ll also build a simple yet styled and accessible Button component using the library.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Use Shadcn UI?
&lt;/h2&gt;

&lt;p&gt;Below are some compelling reasons why developers are turning to Shadcn UI:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Built with Radix UI Primitives&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Shadcn UI leverages Radix UI for accessibility and behavior, ensuring components are built with accessibility best practices out of the box.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Full Control of Styling&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Unlike traditional UI libraries, Shadcn UI doesn’t abstract styling away. You get full control with Tailwind CSS and can easily theme or extend components as needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Copy-Paste Component Model&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead of a bloated npm package, Shadcn gives you the flexibility to copy only the components you need into your codebase — no unnecessary bundle size penalties.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. TypeScript-First&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Components are built with TypeScript, providing excellent type safety and IDE support.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Easily Maintainable and Customizable&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Since the components live in your codebase, you can modify, optimize, and maintain them like any of your own custom components.&lt;/p&gt;




&lt;h2&gt;
  
  
  Setting Up Shadcn UI in a React + TypeScript Project
&lt;/h2&gt;

&lt;p&gt;Let’s walk through integrating Shadcn UI into a new Vite + React + TypeScript project and using the Button component.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Create a New Vite + React + TypeScript App
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm create vite@latest my-shadcn-app -- --template react-ts
cd my-shadcn-app
npm install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Install Tailwind CSS
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Edit your &lt;code&gt;tailwind.config.ts&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;import type { Config } from "tailwindcss";&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const config: Config = {
  content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
  theme: {
    extend: {},
  },
  plugins: [],
};

export default config;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;src/index.css&lt;/code&gt;, add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@tailwind base;
@tailwind components;
@tailwind utilities;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Install and Initialize Shadcn UI
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install shadcn@latest
npx shadcn@latest init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;During the prompt, you will be asked:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which color would you like to use as the base color? — choose desired color&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This generates a &lt;code&gt;components&lt;/code&gt; folder with a utility-based setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Add the Button Component
&lt;/h2&gt;

&lt;p&gt;To install a Button component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx shadcn@latest add button
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a reusable Button.tsx component inside your components/ui folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"

import { cn } from "@/lib/utils"

const buttonVariants = cva(
  "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&amp;amp;_svg]:pointer-events-none [&amp;amp;_svg:not([class*='size-'])]:size-4 shrink-0 [&amp;amp;_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
  {
    variants: {
      variant: {
        default:
          "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
        destructive:
          "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
        outline:
          "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
        secondary:
          "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
        ghost:
          "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
        link: "text-primary underline-offset-4 hover:underline",
      },
      size: {
        default: "h-9 px-4 py-2 has-[&amp;gt;svg]:px-3",
        sm: "h-8 rounded-md gap-1.5 px-3 has-[&amp;gt;svg]:px-2.5",
        lg: "h-10 rounded-md px-6 has-[&amp;gt;svg]:px-4",
        icon: "size-9",
      },
    },
    defaultVariants: {
      variant: "default",
      size: "default",
    },
  }
)

function Button({
  className,
  variant,
  size,
  asChild = false,
  ...props
}: React.ComponentProps&amp;lt;"button"&amp;gt; &amp;amp;
  VariantProps&amp;lt;typeof buttonVariants&amp;gt; &amp;amp; {
    asChild?: boolean
  }) {
  const Comp = asChild ? Slot : "button"

  return (
    &amp;lt;Comp
      data-slot="button"
      className={cn(buttonVariants({ variant, size, className }))}
      {...props}
    /&amp;gt;
  )
}

export { Button, buttonVariants }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5: Use the Button in Your App
&lt;/h2&gt;

&lt;p&gt;Update &lt;code&gt;App.tsx&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Button } from "@/components/ui/button";

function App() {
  return (
    &amp;lt;div className="flex h-screen items-center justify-center bg-gray-100"&amp;gt;
      &amp;lt;Button variant="default" onClick={() =&amp;gt; alert("Shadcn Button Clicked")}&amp;gt;
        Click Me
      &amp;lt;/Button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The variant="default" prop controls the button style, and you can customize or create your own variants by editing the component’s classNames.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Shadcn UI Library brings a new approach to component libraries: opinionated yet fully customizable, accessible yet unrestrictive. It gives developers control without compromising on design consistency or accessibility standards.&lt;/p&gt;

&lt;p&gt;Whether you’re building an internal dashboard or a polished product UI, Shadcn UI is worth exploring — especially if you’re already using Tailwind CSS and want an ergonomic and maintainable component structure.&lt;/p&gt;

&lt;p&gt;If you’re tired of bloated UI frameworks and want to own your UI code, Shadcn UI Library may be exactly what you need.&lt;/p&gt;

</description>
      <category>css</category>
      <category>frontend</category>
      <category>react</category>
      <category>ui</category>
    </item>
  </channel>
</rss>
