Integrating with Shadcn: Tips and Insights for Seamless UI Component Integration

Posted by Aug on June 8, 2024

Abstract:
This post shares a developer’s experience integrating Shadcn UI components into a Next.js project. It covers essential aspects such as initial project preparation, adapting to Shadcn’s opinionated styling (including dark theme and “New York” style), managing global CSS to avoid conflicts, and provides an example root layout that incorporates ThemeProvider and the Shadcn Toaster component.

Estimated reading time: 3 minutes

Integrating with Shadcn: My Experience and Insights

I want to share my experience integrating Shadcn UI components. Here are some things I encountered.

Project Preparation

Before starting the integration, prepare your project by following the official Shadcn documentation: https://ui.shadcn.com/docs/installation/next

Opinionated Styling

The Shadcn example at https://ui.shadcn.com/ has strong default settings (it’s “opinionated”). It assumes you’re using a dark theme and their “New York” visual style. This means your main layout file needs to use their theme provider. Since my website has a black background by default, I had to use the dark theme for the Shadcn components to look right.

1
2
3
4
5
6
7
8
<ThemeProvider
  attribute="class"
  defaultTheme="dark"
  enableSystem
  disableTransitionOnChange
>
  {/* Your content */}
</ThemeProvider>

Styling Considerations

The standard Shadcn setup uses a “slate” color style and replaces CSS variables (this is set with "cssVariables": true in the components.json file). I didn’t use their font styling. Instead, I had to move all my main CSS styles to my own file (/styles/mystyles.css) because Shadcn overwrites the usual /src/app/globals.css file.

New York Styling

The example components I’m using have the “New York” style. For instance, to use the toast notification shown in the profile update example at https://ui.shadcn.com/examples/forms, I had to add the NewYorkToaster component (from "@/registry/new-york/ui/toaster") to my main layout file, just above my footer. This was necessary for the profile update toast notification to work correctly with their example form.

Root Layout Example

For reference, here is my main layout file. It includes authentication, the theme provider, internationalization (next-intl), and the New York styled toaster notification:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import { NextIntlClientProvider, useMessages } from "next-intl";
import type { Metadata } from "next";
import "../globals.css";
import "../../../styles/fonts.css";
import "../../../styles/mystyles.css";
import Footer from "../../components/Footer";
import GoogleAnalytics from "../../components/GoogleAnalytics";
import { AuthProvider } from "../../hooks/Auth";
import { ThemeProvider } from "@/components/theme-provider";
import { Toaster as NewYorkToaster } from "@/registry/new-york/ui/toaster";

export const metadata: Metadata = {
  title: "8-Bit Oracle - Generative I-Ching Fortuneteller",
  description: "Generative I-Ching Fortuneteller",
};

export default function LocaleLayout({
  children,
  params: { locale },
}: {
  children: React.ReactNode,
  params: { locale: string },
}) {
  const messages = useMessages();
  return (
    <html lang={locale} suppressHydrationWarning>
      <head>
        <GoogleAnalytics />
      </head>
      <body className="text-green">
        <ThemeProvider
          attribute="class"
          defaultTheme="dark"
          enableSystem
          disableTransitionOnChange
        >
          <NextIntlClientProvider locale={locale} messages={messages}>
            <AuthProvider>
              <main>{children}</main>
              <NewYorkToaster />
              <Footer />
            </AuthProvider>
          </NextIntlClientProvider>
        </ThemeProvider>
      </body>
    </html>
  );
}

Conclusion

Overall, the developer experience with Shadcn is quite good. However, you definitely need to explore their sample project to understand the actual implementation details to get the components working correctly. It’s not always as simple as just copying and pasting the component code, even though their documentation might suggest that.