DEV Community

Cover image for Getting started with Shadcn/UI in React: A practical guide
Joseph Muchai
Joseph Muchai

Posted on • Originally published at blog.stackademic.com

Getting started with Shadcn/UI in React: A practical guide

Introduction

The front-end development world is ever-changing. Front-end developers seek new ways to create high-quality, accessible, visually appealing user interfaces for websites and apps. This drives React developers to constantly search for tools and libraries that can simplify their development process and help them create amazing user interfaces. This is where Shadcn/UI comes in.

It is a collection of beautifully designed user interface (UI) components that you can easily copy and paste into your applications. Developers can use it with any framework that supports React, like Next, Gatsby, Remix, and others.

In this practical guide, let us explore some of its key features, how to get started, and implement some hands-on examples. To fully understand the contents of this guide, you should have a good understanding of React and Tailwind CSS.


What is Shadcn/UI?

It is an open-source UI library that offers a comprehensive list of reusable front-end components designed for modern React applications. It takes a distinctly different approach from the more opinionated UI libraries like Material UI (MUI) or Bootstrap. While those libraries often have rigid, predefined styles and components, Shadcn/UI aggressively focuses on minimalism, accessibility, and customizability.

It is not distributed via the node package manager (npm) as a dependency. Most UI libraries (such as MUI, Bootstrap, Chakra UI, etc.), are distributed as npm packages which means you install them using npm install "library-name", and then you get all of the library UI components added to your code in the node_modules as dependencies.

However, for Shadcn/UI, developers run commands on the shadcn command line interface(shadcn-cli) to selectively add components directly into their project. The npx command, which allows running a package without needing to install the package globally, is used. For example, npx shadcn-ui@latest add button fetches the latest shadcn-cli version and runs the command to copy a button component's code directly into your project, not the node_modules.

This approach allows you to selectively integrate only the necessary components, providing greater flexibility and customization. When developers package components in an npm package, they couple the style with the implementation, resulting in less customizable code.

To clarify, running npm install shadcn-ui installs the shadcn-cli and not the actual UI library. This is unnecessary since you can execute the shadcn-cli using npx without installing it globally.

It is built with Tailwind in its foundation and incorporates components and techniques from the Radix UI. This combination of Tailwind and Radix UI allows for a unique blend of design flexibility, accessibility, and development speed. Developers can leverage the utility-first classes provided by Tailwind to style their components quickly.


Why use Shadcn/UI?

Using it in your React projects offers several key benefits. Let's explore each one:

  • Accessibility: The components adhere to the Web Content Accessibility Guidelines (WCAG), and provide keyboard navigation, screen reader support, and other accessibility features out of the box.

  • Customizability: Developers can tailor the look and feel of each component to ensure it harmonizes with their application's overall design language. By decoupling component design from implementation, you get easier updates, scalability, and style swapping without affecting core functionality.

  • Modularity: Developers can select specific components to copy and paste directly into their projects. This approach promotes modularity and maintainability, making developers update, scale, and style components more easily.

  • Ease of use: Components offer a simple copy-paste approach that empowers developers with ownership and granular control over the codebase. Developers can now shape and style the components according to their unique preferences and requirements.

  • Utility-first design: By leveraging Tailwind, there is a utility-first design approach, allowing you to apply styles and customize the appearance of your components quickly. Hence, faster development times and a more streamlined design process, as you don't write as much custom CSS.

  • Amazing documentation: The documentation is great, with clear explanations, code examples, and guidelines for using the library effectively.


Getting Started

Now, let us cover how to set up Shadcn/UI in a React project using Vite without Typescript. You can check out the documentation for more instructions on integrating with other frameworks.

  • Use your terminal or command line interface to create a new React project.

    npm create vite@latest my-shadcn-app -- --template react
    

    A new directory called my-shadcn-app is created with a basic React project structure.

  • Add Tailwind.

    After navigating to the my-shadcn-app project with your IDE, in the terminal run the commands below to install Tailwind and its peer dependencies.

    npm install -D tailwindcss postcss autoprefixer
    

    This will generate thetailwind.config.js and postcss.config.js files.

    npx tailwindcss init -p
    
  • Create and edit a jsconfig.json file: Since we are not using typescript we do not have a tsconfig.json file like in the documentation. Hence, create a jsconfig.json file. In this file, add the following code to tell the JavaScript language service to map the@ symbol to the ./src/ directory, allowing you to use the @ symbol when importing components or modules from your project's src directory:

jsconfig code block

  • Update vite.config.js:

    First, install one more required dependency:

    npm i -D @types/node
    

    Add the following configuration to ensure that Vite can resolve the paths using the @ symbol in your imports:

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"),
    },
  },
});
Enter fullscreen mode Exit fullscreen mode
  • Add Shadcn/UI

    To install dependencies and set up the necessary files and structure for you to start using the reusable components, run:

    npx shadcn-ui@latest init
    

    The terminal will then prompt you for additional configurations. A preview of my responses:

preview of terminal responses

  • Add a component: You can create a component by copying its code from the specified documentation or adding it through the terminal.

    As an illustration, let us install a button component using the terminal. This component's code will be in the components folder after installation. It will provide everything you need to create your Button component template.
    Run the command:

    npx shadcn-ui@latest add button
    

    The result:

button component code

To use the Button component in your code import it like any other regular React component. You can customize its appearance by passing in the variant and size props.

import "./App.css";
import { Button } from "./components/ui/button";

function App() {
  return (
    <>
      <Button variant="ghost" size="lg">
        Click me
      </Button>
    </>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

More on themes and the theme editor

Shadcn/UI offers a unique approach to theming by providing hand-picked themes that developers can copy and paste into their applications. You can customize these themes manually in your code by tweaking the default variables or using the theme editor online.

The online theme editor is more developer-friendly and provides a visual interface for configuring the style, color, border-radius, and mode (light/dark). A preview of the theme editor:


Sample implementations with real-world UI examples

Now, we will dive into some real-world UI scenarios to explore the components:

Carousel and Card: A simple product gallery

A common UI element used in e-commerce websites is the carousel or image slider, which allows customers to preview product images. In this section, we will build a 'trending products' section for an online sneaker store.

The Carousel component from Shadcn/UI is built using the Embla carousel library. We will use this and the Card component to create a smooth and responsive image slider for product showcasing.

To begin, add the Carousel and Card components to your project:

npx shadcn-ui@latest add card
Enter fullscreen mode Exit fullscreen mode

and

npx shadcn-ui@latest add carousel
Enter fullscreen mode Exit fullscreen mode

After installation, import these components from @/components/ui. The Card, CardContent, and CardTitle will structure and style the individual product cards. For the scrollable and interactive product showcase, import the Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious.

import * as React from "react";
import { Card, CardContent, CardTitle } from "@/components/ui/card";
import {
  Carousel,
  CarouselContent,
  CarouselItem,
  CarouselNext,
  CarouselPrevious,
} from "@/components/ui/carousel";
Enter fullscreen mode Exit fullscreen mode

The App function in the App.jsx is the main React component that will render the UI. The products array initializes dummy product data, where each object represents a product with a name and an image.

In the return statement place a div container styled with Tailwind to center the content and provide padding and a h1 element displaying the title "Trending Products".
The Carousel component wraps all the product items, setting constraints for its width at different screen sizes.

function App() {
  const products = [
    {
      name: " Air max 90 PREMIUM Curry",
      image: "/src/assets/Air-max.jpg",
    },
    {
      name: "Air Jordan 1 High OG",
      image: "/src/assets/Air-1.jpg",
    },
    {
      name: "Puma RSX Pink",
      image: "/src/assets/puma-rsx-pink.jpg",
    },
    {
      name: "Air Force 1",
      image: "/src/assets/shoe.jpg",
    },
    {
      name: "Nike SuperRep Go",
      image: "/src/assets/super.jpg",
    },
    {
      name: "Air Jordan 12",
      image: "/src/assets/jordan-12.jpg",
    },
    {
      name: "Puma RSX Pink",
      image: "/src/assets/puma-rsx-pink.jpg",
    },
  ];

  return (
    <>
      <div className="flex flex-col items-center justify-center py-8">
        <h1 className="text-2xl font-bold mb-6">Trending Products:</h1>
        <Carousel className="w-full max-w-[90%] md:max-w-[80%] lg:max-w-[80%]">
            // Carousel content will go here...
        </Carousel>
      </div>
    </>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Within the Carousel component wrap the entire image slider with the CarouselContent component. The products.map() method iterates over each product in the array, creating a CarouselItem for each. The key attribute will ensure that each item is uniquely identifiable.

The Tailwind utility class basis in the CarouselItem sets the number of products shown at different screen sizes. Each product item in CarouselItem will be wrapped in a Card component containing the img element to showcase the product image and a CardContent component that overlays the image with the product name.
Outside of the CarouselContent, the CarouselPrevious and CarouselNext components are used to navigate through the carousel items.

<Carousel className="w-full max-w-[90%] md:max-w-[80%] lg:max-w-[80%]">
  <CarouselContent>
    {products.map((product, index) => (
      <CarouselItem
        key={index}
        className="sm:basis-1/1 md:basis-1/2 lg:basis-1/3"
      >
        <Card className="h-full">
          <div className="relative h-[300px]">
            <img
              src={product.image}
              alt={product.name}
              className="h-full w-full object-cover"
            />
            <CardContent className="absolute bottom-0 left-0 right-0 bg-white/70 p-4">
              <CardTitle>{product.name}</CardTitle>
            </CardContent>
          </div>
        </Card>
      </CarouselItem>
    ))}
  </CarouselContent>
  <CarouselPrevious className="absolute left-2 top-1/2 -translate-y-1/2" />
  <CarouselNext className="absolute right-2 top-1/2 -translate-y-1/2" />
</Carousel>;
Enter fullscreen mode Exit fullscreen mode

This implementation creates a responsive product gallery with a carousel, displaying product images and names in a visually appealing manner:

Accordion: A Frequently Asked Questions(FAQ) section

A Frequently Asked Questions (FAQ) page is an integral part of any SaaS (Software as a Service) platform. It addresses the user's most common questions, removing the need to search through extensive documentation for information.

The accordion is a vertically stacked set of interactive headings that reveal a section of content. It is the perfect component for building a FAQ section or page. Here, we will implement a responsive FAQ page for an artificial intelligence SaaS platform.

Start by installing the Accordion component:

npx shadcn-ui@latest add accordion
Enter fullscreen mode Exit fullscreen mode

The components Accordion, AccordionItem, AccordionTrigger, and AccordionContent will be imported from the ui folder under components and into the App.jsx. These components will be essential for creating an accordion-style interface.

import {
  Accordion,
  AccordionItem,
  AccordionTrigger,
  AccordionContent,
} from "@/components/ui/accordion";
Enter fullscreen mode Exit fullscreen mode

In the App function, initialize the faqs array with a set of FAQ objects, each containing a question and an answer. This data structure will allow for easy iteration and dynamic rendering of each FAQ item.

In the return statement, a div container houses our entire implementation. Within this div we will have a h2 element displaying the title "Frequently Asked Questions," centered and styled for emphasis. Another div will be used to wrap around the actual Accordion component.

function App() {
  const faqs = [
    {
      question: "How does your AI SaaS platform work?",
      answer:
        "Our AI SaaS platform leverages advanced machine learning algorithms to provide intelligent solutions for our customers. Users can access a wide range of features and tools to enhance their workflows and decision-making processes.",
    },
    {
      question: "What kind of AI models does the platform support?",
      answer:
        "The platform supports a variety of AI models, including natural language processing, computer vision, and predictive analytics. We are constantly expanding our AI capabilities to meet the evolving needs of our customers.",
    },
    {
      question: "How secure is the data on your platform?",
      answer:
        "Data security and privacy are our top priorities. We employ industry-leading encryption and access controls to ensure the confidentiality and integrity of our customer's data. Our platform is regularly audited and certified to meet the highest security standards.",
    },
    {
      question: "Do you offer any integration options?",
      answer:
        "Yes, our AI SaaS platform integrates seamlessly with several business software and tools, including CRM, ERP, and project management systems. This allows our customers to incorporate the AI into their existing workflows.",
    },
  ];

  return (
    <>
      <div className="max-w-5xl mx-auto py-12">
        <h2 className="text-3xl font-bold mb-8 text-center mb-10">
          Frequently Asked Questions.
        </h2>
        <div className="md:flex gap-2">
          // image and accordion component will be here...
        </div>
      </div>
    </>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

In the div that will wrap around the Accordion component, initialize two divs:

The first div will have an image element visible only on medium and larger screens (md:block). The image will be aligned to take half the available width (md:w-1/2), providing a visual complement to the FAQs.

The second div will also take half the width on medium and larger screens and contain the Accordion component. The Accordion component will be initialized with the type="single" and collapsible props, meaning only one accordion item can be open at a time, and the user can collapse the open item.

The faqs.map() method iterates through the array of FAQ objects, generating an AccordionItem for each. Inside each AccordionItem, the AccordionTrigger will display the question (faq.question) as a clickable heading (h3). The AccordionContent reveals the corresponding answer (faq.answer) when the item is expanded.

<div className="md:flex gap-2">
  <div className="md:w-1/2 hidden md:block h-8 m-9">
    <img
      src="/src/assets/artAI.jpg"
      alt="AI Assistant"
      className="w-64 h-auto"
    />
  </div>
  <div className="md:w-1/2">
    <Accordion type="single" collapsible>
      {faqs.map((faq, index) => (
        <AccordionItem value={`item-${index}`} key={index}>
          <AccordionTrigger>
            <h3 className="text-lg font-medium">{faq.question}</h3>
          </AccordionTrigger>
          <AccordionContent>
            <p>{faq.answer}</p>
          </AccordionContent>
        </AccordionItem>
      ))}
    </Accordion>
  </div>
</div>;
Enter fullscreen mode Exit fullscreen mode

Finally, export the App component as the default export:

export default App;
Enter fullscreen mode Exit fullscreen mode

The outcome is a clean and organized FAQ section which users can easily interact with:

FAQ page preview

Aspect ratio: Responsive YouTube Video Embed

Embedding YouTube videos is common in many web applications, especially content-driven ones like blogs, tutorials, or educational platforms. Implementing video embeds in React applications can sometimes be a pain since you apply extra CSS styles to achieve responsiveness.

The AspectRatio component allows us to create consistent and visually appealing display layouts. You can use it with images or videos. In this section, we implement a simple blog that embeds a YouTube video.

First, add the AspectRatio component:

npx shadcn-ui@latest add aspect-ratio
Enter fullscreen mode Exit fullscreen mode

Then, import the AspectRatio component from our project's UI components directory. This component will help maintain a consistent aspect ratio for our embedded video.

import { AspectRatio } from "./components/ui/aspect-ratio";
Enter fullscreen mode Exit fullscreen mode

Next, define a VideoEmbed function component. This component will render a YouTube video embedded within an AspectRatio wrapper to maintain a 16:9 aspect ratio.

The iframe element within the AspectRatio component will embed the YouTube video. Set various attributes on the iframe to control its behavior and appearance, including the video source, title, and allowed features.

function VideoEmbed() {
  return (
    <AspectRatio ratio={16 / 9}>
      <iframe
        src="https://www.youtube.com/embed/AqmMx_JidGo?si=1A9BJFdRBaq5axwv"
        title="YouTube video player"
        frameBorder="0"
        allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
        allowFullScreen
        className="w-full h-full"
      />
    </AspectRatio>
  );
}
Enter fullscreen mode Exit fullscreen mode

The main App function component will structure the layout of our page. Wrap the content in a div container with Tailwind CSS classes to set maximum width, center the content, and add padding. Inside this container, place a h1 element for the main title, styled with Tailwind for size, weight, and margin, and a paragraph of lorem ipsum text above the video embed. Also, place the VideoEmbed component defined earlier and a paragraph of text below the video embed.

function App() {
  return (
    <>
      <div className="max-w-5xl mx-auto py-2 px-5">
        <h1 className="text-3xl font-bold mb-4">A glimpse into Shadcn/ui</h1>
        <p className="mb-8">
          Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec
          suscipit semper neque sed imperdiet. Suspendisse ac urna luctus,
          tincidunt mauris sit amet, fringilla enim. Etiam quis neque in leo
          sollicitudin maximus. Aenean at pulvinar elit. Morbi viverra quam
          tempor nunc sollicitudin fringilla. Nullam malesuada vestibulum
          congue. Aliquam ac ante gravida, dapibus ante nec, congue nisl.
          Maecenas orci purus, porttitor non enim non, ultrices faucibus est.
          Nullam vitae odio fringilla, molestie ante ut, luctus ante.
        </p>
        <VideoEmbed />
        <p>
          Neque porro quisquam est qui dolorem ipsum quia dolor sit amet,
          consectetur, adipisci velit...
        </p>
      </div>
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

Finally, export the App component as the default export:

export default App;
Enter fullscreen mode Exit fullscreen mode

This implementation creates a page with a title, introductory text, an embedded YouTube video maintained at a 16:9 aspect ratio, and a concluding text. The layout is responsive and centered on the page, providing a clean and organized content presentation.

The result:

Blog page preview

Command and Sheet: Collapsible sidebar

A popular UI navigation pattern is the sidebar. For easier accessibility on smaller devices, it is made collapsible. We will implement it using the command and sheet components.

The command component allows us to create a command menu for react that offers functionality like displaying suggestions, settings, and more in a command-like interface. It uses the cmdk component, a combo box search, and command component.

The sheet component extends the dialog component to display content that complements the main content of the screen from the official documentation. It is a good option when building components that require user interaction, such as menus and modal dialogs.

In our example, we will combine these 2 to build a collapsible sidebar for a project management tool.

First, install the needed components. Using the npm command line interface:

npx shadcn-ui@latest add sheet
Enter fullscreen mode Exit fullscreen mode

and then,

npx shadcn-ui@latest add command
Enter fullscreen mode Exit fullscreen mode

Then, import the necessary components from our project's UI components folder. These include the Command components for creating a command palette interface, Sheet components for a sliding panel, and the Button component for our menu trigger. We will also import several icons from the lucide-react library to enhance our UI.

import {
  Command,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
  CommandSeparator,
} from "@/components/ui/command";
import {
  Sheet,
  SheetContent,
  SheetDescription,
  SheetHeader,
  SheetTitle,
  SheetTrigger,
} from "@/components/ui/sheet";
import { Button } from "./components/ui/button";
import {
  BriefcaseIcon,
  FolderClosedIcon,
  LayoutDashboardIcon,
  LogOutIcon,
  MenuIcon,
  ReceiptEuroIcon,
  SettingsIcon,
  UserIcon,
  UsersIcon,
} from "lucide-react";
Enter fullscreen mode Exit fullscreen mode

In our App function in App.jsx, structure a sliding menu panel using the Sheet component. The SheetTrigger will contain a Button component with a MenuIcon, which will open the sliding panel when clicked.

Inside the SheetContent, set up the structure of our sliding panel. Use SheetHeader to display the user's name and role, followed by a Command component to create an interactive command palette.

function App() {
  return (
    <>
      <Sheet>
        <SheetTrigger>
          <Button variant="ghost">
            <MenuIcon name="menu" className="h-6 w-6" />
          </Button>
        </SheetTrigger>
        <SheetContent side="left" className="w-[370px]">
          <SheetHeader>
            <SheetTitle>John Doe</SheetTitle>
            <SheetDescription>Project Manager</SheetDescription>
            <Command>
              // Command input and list components will go here...
            </Command>
          </SheetHeader>
        </SheetContent>
      </Sheet>
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

Within the Command component, add a CommandInput for user searches, and a CommandList to display various options. Use CommandGroup components to organize our options into categories, and CommandItem components for individual menu items. Each CommandItem will contain an icon and a link.

<Command>
  <CommandInput placeholder="Type a command or search..." />
  <CommandList>
    <CommandEmpty>No results found.</CommandEmpty>
    <CommandGroup heading="Suggestions">
      <CommandItem>
        <LayoutDashboardIcon className="h-6 w-6" />{" "}
        <a href="#" className="px-4">
          Dashboard
        </a>
      </CommandItem>
      <CommandItem>
        <BriefcaseIcon className="h-6 w-6" />{" "}
        <a href="#" className="px-4">
          Projects
        </a>
      </CommandItem>
      <CommandItem>
        <FolderClosedIcon className="h-6 w-6" />{" "}
        <a href="#" className="px-4">
          Tasks
        </a>
      </CommandItem>
      <CommandItem>
        <UsersIcon className="h-6 w-6" />{" "}
        <a href="#" className="px-4">
          Team
        </a>
      </CommandItem>
    </CommandGroup>
    <CommandSeparator />
    <CommandGroup heading="Settings">
      <CommandItem>
        <UserIcon className="h-6 w-6" />{" "}
        <a href="#" className="px-4">
          Profile
        </a>
      </CommandItem>
      <CommandItem>
        <ReceiptEuroIcon className="h-6 w-6" />{" "}
        <a href="#" className="px-4">
          Billing
        </a>
      </CommandItem>
      <CommandItem>
        <SettingsIcon className="w-6 h-6" />{" "}
        <a href="#" className="px-4">
          Settings
        </a>
      </CommandItem>
      <CommandItem>
        <LogOutIcon className="w-6 h-6" />{" "}
        <a href="#" className="px-4">
          Logout
        </a>
      </CommandItem>
    </CommandGroup>
  </CommandList>
</Command>
Enter fullscreen mode Exit fullscreen mode

To style the components, add custom theme tokens to the index.css file. These tokens will define the background, accent, and accent foreground colors for our theme.

@layer base {
  :root {
    --background: 0 0% 100%;
    --accent: 210 40% 96.1%;
    --accent-foreground: 222.2 47.4% 11.2%;
  }
}
Enter fullscreen mode Exit fullscreen mode

This implementation creates a sliding menu panel with a command palette interface, allowing users to navigate quickly through sections of the application. The panel is triggered by a menu button and slides in from the left side of the screen. The command palette provides a search input and categorized menu items, each with an associated icon for easy recognition.

The result:

Dialog and Tabs: Sign-up/Sign-in pop-up

The dialog component is a modal window that appears above the main app content to provide critical contextual information or ask for a decision. It can create interactive command menus, modal dialogs, and other UI elements that require user interaction.

The tabs component allows for the creation of tabbed navigation in a user interface. Tabbed navigation helps conserve screen real estate, which is particularly useful for mobile applications or websites where space is limited.

We will use these components to create a Sign-up/Sign-in pop-up section.

To begin, install the required components:

npx shadcn-ui@latest add tabs
Enter fullscreen mode Exit fullscreen mode
npx shadcn-ui@latest add dialog
Enter fullscreen mode Exit fullscreen mode
npx shadcn-ui@latest add input
Enter fullscreen mode Exit fullscreen mode

and

npx shadcn-ui@latest add label
Enter fullscreen mode Exit fullscreen mode

Then, import the necessary components. These include the Button, Dialog, Input, Label, and Tabs components, along with their related subcomponents. These will create an interactive sign-up and sign-in form within a modal dialog.

import { Button } from "./components/ui/button";
import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
Enter fullscreen mode Exit fullscreen mode

In the App function, structure a modal dialog using the Dialog component. The DialogTrigger will contain a Button component with the text "Join in", which will open the modal when clicked.

Inside the DialogContent, set up a tabbed interface using the Tabs component. This will allow users to switch between sign-up and sign-in forms. The defaultValue="Sign up" ensures that the "Sign up" tab is selected by default when the dialog opens. Use the TabsList and TabsTrigger components to create the tab navigation.

function App() {
  return (
    <>
      <Dialog>
        <DialogTrigger asChild>
          <Button>Join in</Button>
        </DialogTrigger>
        <DialogContent className="sm:max-w-[455px]">
          <Tabs defaultValue="Sign up" className="w-[400px]">
            <TabsList className="grid w-full grid-cols-2">
              <TabsTrigger value="Sign up">Sign up</TabsTrigger>
              <TabsTrigger value="Sign in">Sign in</TabsTrigger>
            </TabsList>
            // Tab content will go here...
          </Tabs>
        </DialogContent>
      </Dialog>
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

Within each TabsContent, create form fields using the Label and Input components.

The TabsContent with value="Sign up" contains the form fields for signing up, including inputs for the user's name, email, and password. Similarly, the TabsContent with value="Sign in" includes form fields for signing in, with inputs for the user's email and password. Each form will end with a submit button.

<TabsContent value="Sign up">
  <div className="space-y-2">
    <Label htmlFor="name">Your Name</Label>
    <Input placeholder="Name" />
  </div>
  <div className="space-y-1">
    <Label htmlFor="email">Your email address</Label>
    <Input placeholder="Email" />
  </div>
  <div className="space-y-1">
    <Label htmlFor="password">Build a password</Label>
    <Input placeholder="Password" type="password" />
  </div>
  <Button className="w-full my-4">Sign up</Button>
</TabsContent>

<TabsContent value="Sign in">
  <div className="space-y-2">
    <Label htmlFor="email">Your email address</Label>
    <Input placeholder="Email" />
  </div>
  <div className="space-y-1">
    <Label htmlFor="password">Remember your password</Label>
    <Input placeholder="Password" type="password" />
  </div>
  <Button className="w-full my-4">Sign in</Button>
</TabsContent>
Enter fullscreen mode Exit fullscreen mode

To style the component, add custom theme tokens to our index.css file. These tokens will define various color and style properties for our theme, including background colors, text colors, border styles, and more.

@layer base {
  :root {
    --background: 0 0% 100%;
    --foreground: 222.2 84% 4.9%;
    --card: 0 0% 100%;
    --card-foreground: 222.2 84% 4.9%;
    --popover: 0 0% 100%;
    --popover-foreground: 222.2 84% 4.9%;
    --primary: 221.2 83.2% 53.3%;
    --primary-foreground: 210 40% 98%;
    --secondary: 210 40% 96.1%;
    --secondary-foreground: 222.2 47.4% 11.2%;
    --muted: 210 40% 96.1%;
    --muted-foreground: 215.4 16.3% 46.9%;
    --accent: 210 40% 96.1%;
    --accent-foreground: 222.2 47.4% 11.2%;
    --destructive: 0 84.2% 60.2%;
    --destructive-foreground: 210 40% 98%;
    --border: 214.3 31.8% 91.4%;
    --input: 214.3 31.8% 91.4%;
    --ring: 221.2 83.2% 53.3%;
    --radius: 0.5rem;
  }
}
Enter fullscreen mode Exit fullscreen mode

This implementation creates an interactive modal dialog with tabbed sign-up and sign-in forms. The dialog is triggered by a "Join in" button. The forms are styled consistently with the custom theme, providing a cohesive and visually appealing user interface. The tabs allow for a compact design that accommodates new and existing users within the same modal, improving the overall user experience.

The result:


Best Practices

Shadcn/UI ensures a streamlined development experience when working with React. However, for it to be as effective, there are some best practices developers should try to uphold. These include:

  • Performance optimization: Leverage the built-in performance optimizations provided, such as lazy loading and code splitting. Implement efficient state management within the components and use dynamic imports to load components on demand.

  • Maintainability: Adhere to implementation conventions, such as component-based structures, to ensure consistency throughout your codebase. Document your custom components, to make it easier for other developers to understand and contribute to the codebase.

  • Customization and extensibility: Familiarize yourself with the various customization options provided, such as theme configuration and component override. Extend the existing components by creating custom variants or adding new functionality to suit your project's needs. While still adhering to the same design principles and accessibility standards.


Wrapping Up

We have explored the Shadcn/UI library from what makes it stand out from other UI libraries/frameworks to why you should use it as a React developer. The reasons are the unrivaled focus on customizability, accessibility, modularity, ease of use, a utility-first design, and clear documentation.

We have also demonstrated its versatility by building examples using some components. We have implemented a product gallery, a FAQ section, a responsive YouTube embed, a collapsible sidebar, and a sign-up/sign-in pop-up. The code for all the implementations can be found here.

Lastly, we have looked at the best practices, such as optimizing the performance, ensuring maintainability, and carrying out customizations and extensions. All these ensure we leverage it to build robust, visually appealing, and accessible user interfaces.

In conclusion, I hope this blog helps build a better understanding of the library. Happy coding!

Top comments (0)