messageCross Icon
Cross Icon
Web Application Development

Getting Started with SvelteKit and Shadcn-Svelte: A Beginner's Guide

Getting Started with SvelteKit and Shadcn-Svelte: A Beginner's Guide
Getting Started with SvelteKit and Shadcn-Svelte: A Beginner's Guide

Introduction

So you want to build a modern, good-looking web app - but you don't want to spend hours wrestling with CSS or reinventing the wheel for every button and dialog box. That's exactly what this guide covers.

In this tutorial, we're going to walk through how to set up a SvelteKit project and supercharge it with Shadcn-Svelte, a collection of beautiful, accessible UI components that drop right into your project. We'll cover everything from installation to adding components and setting up dark mode.

Whether you're brand new to Svelte or you've played around with it a bit, this guide is written for you. I'll keep things clear and practical.

What you'll need before starting:

  • Node.js installed (^20.19.0 || ^22.13.0 || >=24)
  • A code editor (VS Code works great)
  • Basic familiarity with HTML, CSS, and JavaScript

We’ll create a clean and modern Hero section featuring a smooth Light/Dark mode toggle for a better user experience.

What is Svelte?

If you've used React or Vue before, you already understand the idea of a component-based JavaScript framework: a tool that helps you build UIs by breaking them into reusable pieces.

Svelte does the same thing, but with a twist: it compiles your code at build time instead of running a framework in the browser.

Most frameworks ship a runtime: a chunk of JavaScript that runs in the browser and manages your UI. Svelte doesn't do that. Instead, when you build your project, Svelte converts your components into lean, optimized plain JavaScript. The result is faster load times, smaller bundle sizes, and generally snappier apps.

Here's what Svelte looks like:

Code

<script>
  let count = $state(0);
</script>

<button onclick={() => count++}>
  Clicked {count} times
</button>
      

That's it. No useState, no imports from a library, just clean, readable code that does exactly what it looks like.

SvelteKit is the official full-stack framework built on top of Svelte. Think of it the same way you'd think of Next.js for React. It adds things like:

  • File-based routing - create a file, get a route automatically
  • Server-side rendering (SSR) and static site generation (SSG)
  • API routes - write backend logic right inside your project
  • Layouts - share a common header/footer across multiple pages easily

Bottom line: Svelte is the UI layer, and SvelteKit is the full framework you'll actually build your app with.

What is Shadcn UI?

If you've used React, you might know Shadcn UI, it got popular for one reason: instead of installing a component library as a black-box dependency, you copy the component code directly into your project.

This means you own the code. You can read it, modify it, and style it however you want, no fighting with library internals or overriding deeply nested CSS classes.

Shadcn-Svelte is the Svelte port of that same idea. It gives you a set of beautifully designed, fully accessible components built on top of:

  • Bits UI - headless, accessible Svelte component primitives
  • Tailwind CSS - utility-first CSS for styling
  • tailwind-variants - for managing component style variants cleanly

The components include things like buttons, dialogs, dropdowns, accordions, forms, tooltips, and much more, all styled consistently and ready to use out of the box.

The key difference from other UI libraries: You're not importing from node_modules. The component files live in your src/lib/components/ui/ folder. They're yours to keep and customize.

Setup SvelteKit

Let's get a SvelteKit project up and running. Open your terminal and follow these steps.

Step 1: Create a new SvelteKit project

Code

npx sv create svelte-shadcn
      

You'll be walked through a few prompts. Here's what to pick for this tutorial:

  • Template: SvelteKit minimal
  • Type checking: Yes, use TypeScript (recommended, but optional)
  • Additional options: You can skip extras for now

Once it's done, navigate into your project:

Code

cd svelte-shadcn
      

Step 2: Install dependencies

Code

npm install
      

Step 3: Start the development server

Code

npm run dev
      

Open your browser and go to http://localhost:5173. You should see the default SvelteKit welcome page. Your project is alive!

Your project folder will look something like this:

Code

my-app/
├── src/
│   ├── lib/
│   ├── routes/
│   │   └── +page.svelte      ← your home page
│   └── app.html
|   └── globale.css           ← Create css file
├── static/
├── svelte.config.js
├── vite.config.ts
└── package.json
      

The routes/ folder is where all your pages live. Every +page.svelte file becomes a URL route automatically. Simple and intuitive!

Setup Shadcn-Svelte

Now let's add Shadcn-Svelte to your project.

Step 1: Initialize Shadcn-Svelte

Run the following command in your project root:

Code

npx shadcn-svelte@latest init
      

You'll be asked a few setup questions:

  • Which style would you like to use? : Default (recommended to start)
  • Which color would you like to use as the base color? : Pick whatever you like (Slate, Gray, and Zinc are popular neutral choices)
  • Where is your global CSS file? : src/globale.css
  • Configure the import alias? : Press Enter to accept the default $lib

This command will do several things for you automatically:

  • Install and configure Tailwind CSS
  • Create a components.json config file in your project root
  • Add base CSS variables for theming to your globale.css
  • Set up the component folder at src/lib/components/ui/

Step 2: Check your globale.css

After init, open src/globale.css. You'll notice a bunch of CSS custom properties (variables) have been added — things like --background, --foreground, --primary, etc. These control your app's color scheme for both light and dark mode. You don't need to touch them right now, but it's great to know they're there and editable.

Step 3: Make sure your layout imports the CSS

Open src/routes/+layout.svelte. If it doesn't already import your global styles, add this:

Code

<script>
  import '../globale.css';
</script>

<slot />
      

That's all the setup needed. Shadcn-Svelte is initialized and ready to go!

Add a Component

Let's add some real components and see this all working together. We'll use a Button and an Accordion as our examples.

Adding a Button

Add the button component to your project using the Shadcn CLI:

Code

npx shadcn-svelte@latest add button
      

This copies the button component files into src/lib/components/ui/button/. Now open src/routes/+page.svelte and try it out:

Code

<script>
  import { Button } from '$lib/components/ui/button';
</script>

<main class="p-8 flex gap-4">
  <Button>Default Button</Button>

  <Button variant="outline">Outline</Button>

  <Button variant="destructive">Delete</Button>

  <Button variant="ghost">Ghost</Button>
</main>
      

The variant prop lets you switch between different visual styles. Available variants are default, outline, ghost, destructive, secondary, and link. All the styling is handled via Tailwind under the hood, and since the button file is right in your project, you can open it and customize it any time you want.

Adding an Accordion

The accordion is a perfect example of a more complex interactive component. Add it with:

Code

npx shadcn-svelte@latest add accordion
      

Now use it in your page:

Code

<script>
  import * as Accordion from '$lib/components/ui/accordion';
</script>

<Accordion.Root type="single" class="max-w-md w-full mt-6">
  <Accordion.Item value="item-1">
    <Accordion.Trigger>What is SvelteKit?</Accordion.Trigger>
    <Accordion.Content>
      SvelteKit is the official full-stack framework for Svelte. It handles
      routing, server-side rendering, and much more out of the box.
    </Accordion.Content>
  </Accordion.Item>

  <Accordion.Item value="item-2">
    <Accordion.Trigger>What is Shadcn-Svelte?</Accordion.Trigger>
    <Accordion.Content>
      Shadcn-Svelte is a collection of copy-paste UI components built with
      Tailwind CSS and Bits UI — designed specifically for Svelte projects.
    </Accordion.Content>
  </Accordion.Item>

  <Accordion.Item value="item-3">
    <Accordion.Trigger>Do I need to know Tailwind?</Accordion.Trigger>
    <Accordion.Content>
      Basic Tailwind knowledge helps, but you can get pretty far just using
      the components as-is without touching the underlying styles.
    </Accordion.Content>
  </Accordion.Item>
</Accordion.Root>
      

Notice the import * as Accordion pattern — Shadcn-Svelte components are often made up of multiple sub-components (Root, Item, Trigger, Content) that work together. This composable structure gives you full control over the markup and makes it easy to slot in your own content.

Set Up Dark Mode

One of the best features of Shadcn-Svelte is that dark mode support is baked right into the design system through CSS variables. You just need to wire up the toggle. Here's how.

Step 1: Install mode-watcher

Code

npm install mode-watcher
      

mode-watcher is a small Svelte utility that manages the dark class on your <html> element and automatically persists the user's preference to localStorage.

Step 2: Add ModeWatcher to your root layout

Open src/routes/+layout.svelte and update it:

Code

<script>
  import { ModeWatcher } from 'mode-watcher';
  import '../globale.css';
</script>

<ModeWatcher />

<slot />

      

That's the entire setup. ModeWatcher will detect the user's system preference on first visit and apply the right theme automatically.

Step 3: Add a toggle button

Now let's give users a way to manually switch themes:

Code

<script>
  import { toggleMode } from 'mode-watcher';
  import { Button } from '$lib/components/ui/button';
</script>

<Button onclick={toggleMode} variant="outline">
  Toggle Dark Mode
</Button>
      

Click it and watch your entire app switch between light and dark — all driven by those CSS variables Shadcn-Svelte set up during init. No extra configuration needed.

Tip: Want a sun/moon icon instead of text? Install lucide-svelte and swap in the Sun and Moon icons. You can use the mode store from mode-watcher to know which one to show.

Build a Small Hero Section

This section is all yours! Based on everything we've covered, you've got all the tools you need. Here's a starting structure you can build from and make your own:

Code

bash
npx shadcn-svelte@latest add badge
npm install @lucide/svelte
      

Code

<script>
  import { Button } from '$lib/components/ui/button';
  import { Badge } from '$lib/components/ui/badge';
  import {ArrowRight} from '@lucide/svelte';
  import { toggleMode } from 'mode-watcher';
</script>

<section class="max-w-7xl mx-auto flex flex-col items-center justify-center gap-6 py-24 md:py-32 text-center lg:py-40">
 <Button onclick={toggleMode} variant="outline">
  Toggle Dark Mode
</Button>
  <Badge variant="secondary" class="mb-4">
    <span class="mr-2 rounded-full bg-primary px-1.5 py-0.5 text-xs font-semibold text-primary-foreground">New</span>
    SvelteKit 2.0 is out!
  </Badge>
  
  <h1 class="text-4xl font-bold tracking-tighter sm:text-5xl md:text-6xl lg:text-7xl text-balance max-w-3xl leading-tight">
    Build faster with <span class="bg-linear-to-r from-orange-500 to-red-600 bg-clip-text text-transparent">SvelteKit</span>
  </h1>
  
  <p class="mx-auto max-w-175 text-muted-foreground text-lg sm:text-xl text-balance">
    The modern full-stack framework paired with beautiful, accessible UI components.
    Everything you need to ship production-ready apps Fast.
  </p>
  
  <div class="flex flex-col gap-4 min-[400px]:flex-row justify-center mt-4">
    <Button size="lg" class="gap-2">
      Get Started <ArrowRight class="size-4" />
    </Button>
    <Button size="lg" variant="outline">Learn More</Button>
  </div>
</section>
      

A couple of things worth noting here: text-muted-foreground is a Shadcn CSS variable class that automatically adjusts between light and dark mode — use these theme-aware classes instead of hardcoded colors like text-gray-500 wherever you can. And size="lg" is another Button prop that gives you a larger, more prominent CTA button.

The rest is up to you; add your own copy, images, animations, or whatever fits your project. Have fun with it!

Common Errors

Here are the most common issues people run into when setting up this stack — and exactly how to fix them.

Cannot find module '$lib/components/ui/button'

Why it happens: You're importing a component that hasn't been added to your project yet, or the $lib path alias isn't resolving correctly.

Fix: Make sure you've run the add command for that specific component first:

Code

npx shadcn-svelte@latest add button
      

If the alias is the issue, check that your svelte.config.js has kit.alias set — SvelteKit sets up $lib by default, so you usually won't need to touch this.

❌ Dark mode toggle isn't working

Why does it happen? ModeWatcher isn't mounted in the layout, or mode-watcher wasn't installed.

Fix: First, confirm the package is installed:

Code

npm install mode-watcher
      

Then make sure <ModeWatcher /> is in your +layout.svelte file specifically — not just on a single page. It needs to be in the root layout so it applies across your whole app.

ReferenceError: document is not defined

Why it happens: Some browser-only APIs (like document, window, or localStorage) are running during server-side rendering, where those globals don't exist.

Fix: Wrap browser-only code using SvelteKit's browser check:

Code

<script>
  import { browser } from '$app/environment';

  if (browser) {
    // safe to use document, window, localStorage here
  }
</script>
      

Or use onMount, which only runs in the browser:

Code

<script>
  import { onMount } from 'svelte';

  onMount(() => {
    // this never runs on the server
  });
</script>
      

❌ Component props or events not behaving as expected

Why it happens: Svelte 5 introduced a new reactivity model using "runes" ($state, $props, $derived, etc.) that works differently from Svelte 4. Older tutorials and blog posts often show Svelte 4 syntax, which can cause confusion if you're on a fresh Svelte 5 install.

Fix: Make sure you're using consistent syntax for your Svelte version. If you set up your project recently with npx sv create, you're on Svelte 5. When in doubt, check the Svelte 5 docs or the migration guide.

Conclusion

You're all set! Here's a quick recap of everything we covered:

  • Svelte and SvelteKit - a compile-time framework that produces fast, lean apps with a clean developer experience and file-based routing built in
  • Shadcn-Svelte - a copy-paste component library that gives you full ownership of your UI code, no black boxes
  • Project setup - getting both SvelteKit and Shadcn-Svelte initialized with just a handful of CLI commands
  • Components - adding and composing Button and Accordion components in your pages
  • Dark mode - enabling it with mode-watcher in just a few lines of code
  • Common errors - the most frequent issues and their straightforward fixes

What I love about this stack is how fast you can build something that actually looks good. You're not fighting the framework; everything is designed to work together smoothly.

Reference Github Repo: https://github.com/themeselection/svelte-shadcn-template

From here, explore the full Shadcn-Svelte component library and start pulling in whatever your project needs: dialogs, forms, tooltips, data tables, and more. Every component follows the same pattern you've already learned here, so it'll feel immediately familiar.

You can use Shadcn Studio for your Svelte-based projects. It comes with

With Shadcn Studio, you can speed up your project easily.

Now go build something awesome. 🚀

card user img
Twitter iconLinked icon

Ajay Patel is a guest author and co-founder of Clevision with 15+ years of experience, specializing in AI tools, SaaS, and UI frameworks that accelerate developer innovation.

Frequently Asked Questions

No items found.
Book Your Free Consultation Click Icon

Book a FREE Consultation

No strings attached, just valuable insights for your project

download ready
Thank You
Your submission has been received.
We will be in touch and contact you soon!
View All Blogs