Step-by-step guide for integrating Shadcn UI with React 19.

React 19 pairs seamlessly with Shadcn UI, a utility-based React UI component library known for its flexibility and reusability. Shadcn UI React leverages Tailwind CSS, enabling developers to easily customize and create responsive, accessible components. Unlike traditional React UI libraries, Shadcn UI adds component files directly to your codebase, granting full access to modify styles and props as needed. Theming in Shadcn UI is straightforward, making it highly adaptable to various UI design React requirements.

Step-by-Step Guide to Integrate Shadcn UI with React 19

Detailed step-by-step process for Shadcn UI integration with React 19.

Step 1: Create a New React App

Run the following command to create a new React Vite app with the TypeScript template:

npm create vite@latest react-shadcn-app -- --template react-tsCode language: CSS (css)

Step 2: Navigate to the Project Directory and Test the App

1. Move into the project directory:

cd react-shadcn-app

2. Install dependencies:

npm install

3. Start the app and test it:

npm run dev

Open the app in your browser, e.g., http://localhost:5174. Ensure the default Vite app screen loads successfully.

Vite app screen showing integration of Shadcn UI with React 19.

Step 3: Update to React 19

By default, Vite installs React 18. Update to React 19 using the following command:

npm install react@latest react-dom@latest @types/react@latest @types/react-dom@latestCode language: CSS (css)

Step 4: Install and Configure Tailwind CSS

1. Install tailwindcss and its peer dependencies,

npm install -D tailwindcss postcss autoprefixer

2. Generate tailwind.config.js and postcss.config.js files:

npx tailwindcss init -p

3. Configure Tailwind in src/index.css: Replace the content with:

@tailwind base;
@tailwind components;
@tailwind utilities;Code language: CSS (css)

Remove the default styles from index.css to prevent overriding:

:root {
  font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
  line-height: 1.5;
  font-weight: 400;
  color-scheme: light dark;
  color: rgba(255, 255, 255, 0.87);
  background-color: #242424;
  font-synthesis: none;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
a {
  font-weight: 500;
  color: #646cff;
  text-decoration: inherit;
}
a:hover {
  color: #535bf2;
}
body {
  margin: 0;
  display: flex;
  place-items: center;
  min-width: 320px;
  min-height: 100vh;
}
h1 {
  font-size: 3.2em;
  line-height: 1.1;
}
button {
  border-radius: 8px;
  border: 1px solid transparent;
  padding: 0.6em 1.2em;
  font-size: 1em;
  font-weight: 500;
  font-family: inherit;
  background-color: #1a1a1a;
  cursor: pointer;
  transition: border-color 0.25s;
}
button:hover {
  border-color: #646cff;
}
button:focus,
button:focus-visible {
  outline: 4px auto -webkit-focus-ring-color;
}
@media (prefers-color-scheme: light) {
  :root {
    color: #213547;
    background-color: #ffffff;
  }
  a:hover {
    color: #747bff;
  }
  button {
    background-color: #f9f9f9;
  }
}
Code language: CSS (css)

4. Update tailwind.config.js to include your template paths:

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ["./index.html", "./src/**/*.{ts,tsx,js,jsx}"],
  theme: {
    extend: {},
  },
  plugins: [],
}Code language: JavaScript (javascript)

Step 5: Configure TypeScript and Vite Config

1. Update tsconfig.json for path aliasing:

{
  "files": [],
  "references": [
    {
      "path": "./tsconfig.app.json"
    },
    {
      "path": "./tsconfig.node.json"
    }
  ],
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}
Code language: JSON / JSON with Comments (json)

2. Update tsconfig.app.json for IDE support:

{
  "compilerOptions": {
    // ...
    "baseUrl": ".",
    "paths": {
      "@/*": [
        "./src/*"
      ]
    }
    // ...
  }
Code language: JSON / JSON with Comments (json)

3. Install Node.js types:

npm install -D @types/nodeCode language: CSS (css)

4. Update vite.config.ts file by below contents

import path from "path"
import react from "@vitejs/plugin-react"
import { defineConfig } from "vite"

export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "./src"),
    },
  },
})
Code language: CSS (css)

Step 6: Configure the Shadcn UI Library

1. Run the shadcn UI init command to set up your project:

npx shadcn@latest initCode language: CSS (css)

2. Follow the prompts to configure components.json:

Style: New York
Base color: Zinc
CSS variables for colors: Yes/No (based on preference)Code language: PHP (php)

If you encounter the warning: ‘Some packages may fail to install due to peer dependency issues in npm,’ simply use the –legacy-peer-deps flag. This is necessary because not all supporting packages have been updated yet.”
For more information you can check here: https://ui.shadcn.com/docs/react-19

3. Now you can add components by using below command

npx shadcn@latest add buttonCode language: CSS (css)

If you find the deprecated React.ElementRef in any ShadCN UI component from the ShadCN library, you can replace it with React.ComponentRef.

4. The command above will add the Shadcn UI Button component to your project. You can then import it like this:

import { Button } from "@/components/ui/button"

export default function Home() {
  return (
    <div>
      <Button>Click me</Button>
    </div>
  )
}
Code language: JavaScript (javascript)

5. You can customize the theme to match your project’s styles. Here is a detailed  Shadcn UI tutorial: You can customize the theme and copy it in the index.css file.  Learn More 

Ready to integrate Shadcn UI with React 19?

Step 7: Run and Verify Shadcn Configuration

1. Start the application:

npm run dev

2. Check if Shadcn UI is configured correctly by adding some components and observing their appearance on the web.

To showcase Shadcn’s capabilities, we have integrated some example components into the project. You can find the complete codebase and examples on our GitHub repository

Components Integrated for Demonstration

1 Button

Shadcn provides a customizable Button component with variants like primary, secondary, and outline. You can also add icons and manage states like disabled

Command: npx shadcn@latest add button

Example:

 <Button>Primary</Button>
        <Button variant={"secondary"}>Secondary</Button>
        <Button variant={"outline"}>Outline</Button>
        <Button className="items-center gap-2">
          <Mail className="w-5 h-5" />
          Submit
        </Button>
Code language: HTML, XML (xml)
  • The variant props control the button’s appearance.
  • Icons like Mail can be added inside the button.

2 Input

The Input component is used for various input types, while Textarea provides multi-line input capabilities.

Command: npx shadcn@latest add input

Input Example:

<Input type="email" placeholder="Email" />     
<Input type="password" placeholder="Password" />    
<Input type="file" placeholder="Select Picture" />Code language: HTML, XML (xml)

TextArea Example:

Command – npx shadcn@latest add textarea

<Textarea placeholder="Type your message here." />Code language: HTML, XML (xml)

3 Checkbox

The Checkbox component allows the creation of labeled checkboxes using the Label component.

Command:

npx shadcn@latest add checkbox
npx shadcn@latest add labelCode language: CSS (css)

Example: 

<div className="flex items-center space-x-2">
      <Checkbox id={label} />
      <label
        htmlFor={label}
        className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
        {label}
      </label>
</div>
Code language: HTML, XML (xml)

4 Switch

The Switch component allows the creation of a toggle switch with a label.

Command: npx shadcn@latest add switch
Example:

<div className="flex items-center space-x-2">
      <Switch id={label} />
      <label
        htmlFor={label}
        className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
      >
        {label}
      </label>
</div>
Code language: HTML, XML (xml)
  • The checked prop specifies the current state of the switch.
  • The onCheckedChange callback handles state updates.

5 Select

The Select component provides a powerful dropdown selection experience with customizable elements such as SelectTrigger, SelectContent.

Command: npx shadcn@latest add select

Example: 

<Select>
        <SelectTrigger className="w-[180px]">
          <SelectValue placeholder="Theme" />
        </SelectTrigger>
        <SelectContent>
          <SelectItem value="light">Light</SelectItem>
          <SelectItem value="dark">Dark</SelectItem>
          <SelectItem value="system">Default</SelectItem>
        </SelectContent>
 </Select>
Code language: HTML, XML (xml)
  • SelectTrigger: Defines the dropdown trigger element.
  • SelectContent: Contains the dropdown content.
  • SelectItem: Represents individual selectable items.

6 Popover

The Popover component allows the creation of a customized pop-up trigger and container component.

Command: npx shadcn@latest add popover

Example:

<Popover>
     <PopoverTrigger className="flex w-8 justify-center">
          <Ellipsis />
     </PopoverTrigger>
     <PopoverContent className="flex flex-col w-36">
            <Label className="mb-4">Send Email</Label>
            <Label>Send SMS</Label>
      </PopoverContent>
</Popover>Code language: HTML, XML (xml)
  • PopoverTrigger: Specifies the element that triggers the popover (e.g. an icon).
  • PopoverContent: Contains the popover’s main content 

7 Accordion / Collapsible

The Accordion component allows for the creation of collapsible sections. Below is a guide to implementing the Accordion.

Command: npx shadcn@latest add accordion

Example:

<Accordion type="single" collapsible className="w-full">
   <AccordionItem value="item-1">
        <AccordionTrigger>Personal Information</AccordionTrigger>
        <AccordionContent>
          John Doe is a 28-year-old male with the email
          john.doe@example.com and phone number +1-234-567-890.
        </AccordionContent>
   </AccordionItem>
</Accordion>
Code language: HTML, XML (xml)
  • AccordionTrigger: Acts as the trigger for the accordion item.
  • AccordionContent: Contains the content that will be shown or hidden.

8 Custom Dialog

The Custom Dialog in Shadcn UI serves as a versatile dialog component for the web platform, featuring a custom dialog trigger and customized content.

Command: npx shadcn@latest add dialog

Example: 

<Dialog  open={isDialogVisible} onOpenChange={setDialogVisible}>
        <DialogTrigger asChild>
          <Button className="w-36 ml-4" variant="outline">
            Change Password
          </Button>
        </DialogTrigger>
        <DialogContent className="sm:max-w-[475px]">
          <DialogHeader>
            <DialogTitle>Change Password</DialogTitle>
            <DialogDescription>
              Change your password here. Click save when you're done.
            </DialogDescription>
          </DialogHeader>
          <div className="grid gap-4 py-4">
            <div className="grid grid-cols-3 items-center gap-4">
              <Label htmlFor="password" className="text-right">
                Password
              </Label>
              <Input id="password" type="password" className="col-span-2" />
            </div>
            <div className="grid grid-cols-3 items-center gap-4">
              <Label htmlFor="confirmPassword" className="text-right">
                Confirm Password
              </Label>
              <Input id="confirmPassword" className="col-span-2" />
            </div>
          </div>
          <DialogFooter>
            <Button
              type="submit"
              onClick={() => {
                setDialogVisible(false);
              }}
            >
              Save changes
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>Code language: HTML, XML (xml)
  • DialogTrigger: Triggers the dialog when a button is clicked.
  • DialogContent: Contains the main content of the dialog, including the title, description, and footer buttons.
  • DialogHeader: Contains the dialog header.
  • DialogFooter: Contains the dialog footer buttons.

9 Tabs

The Tabs component allows for tabbed navigation, providing an organized way to switch between different views or sections. 

Command: npx shadcn@latest add tabs

Example: 

<Tabs defaultValue="account" className="w-[400px]  ml-4">
    <TabsList>
          <TabsTrigger value="account">Account Info</TabsTrigger>
          <TabsTrigger value="password">Billing Info</TabsTrigger>
     </TabsList>
     <TabsContent value="account">
          Account Info
     </TabsContent>
     <TabsContent value="password">
          Billing Info
      </TabsContent>
</Tabs>Code language: HTML, XML (xml)
  • TabsList: Manages the tab headers with optional separators.
  • TabsTrigger: Represents an individual tab title.
  • TabsContent: Contains the content displayed based on the selected tab.

10 Table

The Table component allows you to build more complex data tables. By combining it with @tanstack/react-table, you can create tables with sorting, filtering, and pagination.

Command: npx shadcn@latest add table

<Table>
        <TableHeader>
          <TableRow>
            <TableHead className="w-[100px]">Invoice</TableHead>
            <TableHead>Status</TableHead>
            <TableHead className="text-right">Amount</TableHead>
          </TableRow>
        </TableHeader>
        <TableBody>
          {invoices.map((invoice) => (
            <TableRow key={invoice.invoice}>
              <TableCell className="font-medium">{invoice.invoice}</TableCell>
              <TableCell>{invoice.paymentStatus}</TableCell>
              <TableCell className="text-right">
                {invoice.totalAmount}
              </TableCell>
            </TableRow>
          ))}
        </TableBody>
        <TableFooter>
          <TableRow>
            <TableCell colSpan={3}>Total</TableCell>
            <TableCell className="text-right">$2,500.00</TableCell>
          </TableRow>
        </TableFooter>
</Table>Code language: HTML, XML (xml)
  • TableHeader: Defines the header section of the table.
  • TableRow: Represents a row in the table.
  • TableHead: Defines a header cell within a row.
  • TableBody: Contains the body rows with data.
  • TableCell: Represents a cell within a row.
  • TableFooter: Adds a footer row at the bottom of the table.

Here is the sample Shadcn components screen:

Overview of Shadcn UI components for React 19 integration.

Conclusion:

Integrating Shadcn UI with React 19 provides a powerful way to build flexible, reusable, and customizable UI components. With seamless support for Tailwind CSS and a wide variety of utility-based components, Shadcn UI simplifies the creation of responsive and accessible React UI components. From buttons and inputs to complex dialogs and popovers, Shadcn empowers developers to efficiently manage UI elements while maintaining full control over styles and functionality.

By following the step-by-step setup and integration process outlined above, developers can quickly get started with Shadcn UI in their React 19 projects, enhancing the overall development experience and ensuring a smooth, adaptable design system tailored to various project needs.

Master React 19 with Shadcn UI integration.

Author's Bio

Chetan Shelake
Chetan Shelake

Chetan Shelake is a Principal Software Engineer at Mobisoft Infotech with 7.5 years of experience in web, mobile, and backend development. Specializing in React, React Native, and Node, he is dedicated to building innovative and user-friendly applications. Chetan is passionate about delivering scalable solutions and staying ahead in emerging technologies.