Token导航 LogoToken导航

Agent Skill · 前端设计

shadcn-svelte-skill(shadcn/ui Svelte 技能)

用于辅助前端页面、组件、样式和交互逻辑的开发与维护。它适合让 Agent 生成或审查 React、Next.js、Vue、Tailwind、CSS 等相关代码,整理组件结构,或定位布局和性能问题。使用时需要结合项目现有设计系统、路由和构建方式,避免只生成孤立片段;涉及页面改动时,应配合本地预览和构建检查确认视觉效果。

shadcn-svelte-skill 是前端设计类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为需要联网;许可证为 MIT,第三方扫描已通过,按安装量在前端设计类的 10,216 个 Skill 里排第 9,602。

总安装 210周安装 9GitHub Stars 4下载 73核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
MIT

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:shadcn-svelte-skill(shadcn/ui Svelte 技能)
来源仓库:https://github.com/linehaul-ai/linehaulai-claude-marketplace
仓库路径:skills/shadcn-svelte-skill
安装命令:
npx skills add https://github.com/linehaul-ai/linehaulai-claude-marketplace --skill shadcn-svelte-skill
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。不同来源提供的安装方式可能略有差异;本站展示可直接复制的安装命令,安装前请核对来源页面。

skills.shnpx skills
npx skills add https://github.com/linehaul-ai/linehaulai-claude-marketplace --skill shadcn-svelte-skill

这个 Skill 是做什么的

前端设计类 Skill 关注页面结构、视觉规范和组件写法,输出通常是可运行的界面代码。

shadcn-svelte-skill 提供生产级 UI 组件,支持 Svelte 框架开发。适合在 Codex、Claude、Cursor 等宿主中构建可访问的应用界面。通过 npx skills add 命令从指定仓库安装并使用。使用时需结合项目现有设计系统,避免引入依赖锁定风险。

适用宿主包括 Codex、Claude、Cursor、Gemini CLI,接入前应确认版本、权限和运行环境要求。

来源仓库内路径:skills/shadcn-svelte-skill

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/linehaul-ai/linehaulai-claude-marketplace --sk…;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要需要联网,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

shadcn-svelte-skill 怎么安装?

在终端执行 npx skills add https://github.com/linehaul-ai/linehaulai-claude-marketplace --skill shadcn…。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

shadcn-svelte-skill 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

shadcn-svelte-skill 需要什么权限?

权限级别是需要联网。该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

shadcn-svelte-skill 是免费的吗?

来源标注的许可证是 MIT。本站不代收任何费用,也不托管安装包;能否商用、要不要署名,以许可证原文为准。

shadcn-svelte-skill 用的人多吗?

公开数据是累计安装 210 次,近一周安装 9 次,下载 73 次,GitHub 4 星。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

shadcn-svelte-skill 安全吗?

第三方扫描结果为通过,但这只覆盖已知的静态检查项,不能替代自己读一遍源码和安装命令。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。
  • 3 个目录同时收录,说明这个 Skill 流传比较广。
  • 许可证明确为 MIT,商用和分发边界好判断。
  • 第三方扫描已通过,常见的高风险行为没有命中。

先想清楚的地方

  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理前端设计类任务、又不想每次都手写提示词的人。
  • 需要许可证清楚、并且有第三方扫描结果的团队项目。

不太适合

  • 需要厂商级技术支持和 SLA 的生产系统。

前端设计类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
frontend-design

前端设计 · Codex、Claude

8,823,360126,072只读MIT通过
vercel-composition-patterns

Vercel 组合模式 · Codex、Claude

3,858,81625,893需要联网MIT通过
vercel-react-native-skills

Vercel React native skills 前端 · Codex、Claude

2,468,66425,878只读MIT通过
adapt

adapt 搜索 · Codex、Claude

2,027,04023,125操作浏览器未明确通过
bolder

bolder 分析 · Codex、Claude

2,004,28823,130只读未明确通过
shadcn-svelte-skill

shadcn/ui Svelte 技能 · 本页

2104需要联网MIT通过

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

shadcn-svelte with Tailwind v4.1 + Vite

A comprehensive guide for working with shadcn-svelte, the Svelte port of shadcn/ui. This skill covers component installation, customization, and integration patterns for Svelte and SvelteKit projects using Tailwind CSS v4.1 with the @tailwindcss/vite plugin.

When to Use

Use shadcn-svelte when:

  • Building component-based Svelte/SvelteKit applications
  • You need accessible, styled UI elements (buttons, forms, modals, dialogs, etc.)
  • You want customizable components that don't lock you into a UI library
  • You're using Tailwind CSS v4.1 with Vite for zero-runtime CSS
  • You need complex components like data tables, drawers, or navigation menus
  • You want TypeScript support with full type safety

Do NOT use for lightweight static sites or when you prefer minimal dependencies.

Svelte Component Library Ecosystem

While this skill focuses on shadcn-svelte, here's the broader Svelte UI landscape to help you choose:

Library Comparison

LibraryTypeBest ForLearning Curve
shadcn-svelteCopy-paste componentsFull customization, TypeScript-firstMedium
Skeleton UIInstallable packageRapid development, themesLow
Melt UIHeadless primitivesMaximum accessibility controlHigh
CustomBuilt from scratchUnique requirementsVaries

Skeleton UI

Full-featured component library with built-in theming:

npm install @skeletonlabs/skeleton @skeletonlabs/tw-plugin
<script>
  import { AppBar, AppShell } from '@skeletonlabs/skeleton';
</script>

<AppShell>
  <svelte:fragment slot="header">
    <AppBar>My App</AppBar>
  </svelte:fragment>
  <slot />
</AppShell>

Use when: You want rapid development with pre-built themes and don't need deep customization.

Melt UI

Headless, accessible primitives—you bring the styling:

npm install @melt-ui/svelte
<script>
  import { createDialog, melt } from '@melt-ui/svelte';

  const { trigger, overlay, content, title, close } = createDialog();
</script>

<button use:melt={$trigger}>Open</button>

{#if $open}
  <div use:melt={$overlay} class="fixed inset-0 bg-black/50" />
  <div use:melt={$content} class="fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-white p-6 rounded-lg">
    <h2 use:melt={$title}>Dialog Title</h2>
    <button use:melt={$close}>Close</button>
  </div>
{/if}

Use when: You need complete styling control with guaranteed accessibility.

Quick Add Workflow

For simple component additions across libraries:

# shadcn-svelte (recommended for this skill)
npx shadcn-svelte@latest add button card dialog

# Skeleton UI
npm install @skeletonlabs/skeleton

# Melt UI
npm install @melt-ui/svelte

For complex multi-component features, see the workflows.md reference document.

Core Concepts

shadcn-svelte is copy-paste component infrastructure, not a traditional npm package. You own the code—components live in your $lib/components/ui/ directory. This means:

  • Full customization without forking
  • No version lock-in (upgrade on your schedule)
  • TypeScript-first with Svelte 5 reactive variables
  • Tailwind v4.1 with @tailwindcss/vite for zero-runtime styling
  • Built on Bits UI primitives for accessibility
  • CSS variables for dynamic theming

Setup: SvelteKit with Tailwind v4.1

1. Create SvelteKit Project

pnpm dlx sv create my-app
cd my-app

2. Install Tailwind v4.1 + @tailwindcss/vite

pnpm i -D tailwindcss @tailwindcss/vite
pnpm dlx shadcn-svelte@latest init

3. Configure Vite with Tailwind Plugin

Edit vite.config.ts:

import { defineConfig } from 'vite'
import { sveltekit } from '@sveltejs/kit/vite'
import tailwindcss from '@tailwindcss/vite'

export default defineConfig({
  plugins: [tailwindcss(), sveltekit()],
})

4. Update CSS Entry Point

Edit src/app.css (remove old @tailwind directives):

@import "tailwindcss";

/* Your custom CSS here */
@layer utilities {
  .btn-custom {
    @apply px-4 py-2 rounded-lg font-semibold transition-colors;
  }
}

No separate tailwind.config.js needed—Tailwind v4.1 scans content automatically. If you need custom configuration:

// tailwind.config.js (optional)
export default {
  theme: {
    extend: {
      colors: {
        brand: {
          50: '#f9fafb',
          // ...
        },
      },
    },
  },
  plugins: [],
}

5. Ensure CSS is Imported in Layout

Edit src/routes/+layout.svelte:

<script>
  import '../app.css'
</script>

<slot />

The init command:

  • Sets up @tailwindcss/vite plugin in vite.config.ts
  • Creates src/app.css with @import "tailwindcss"
  • Creates the cn() utility function for class merging
  • Configures path aliases

Add Components

# Add individual components
pnpm dlx shadcn-svelte@latest add button

# Add multiple at once
pnpm dlx shadcn-svelte@latest add card alert dialog

# Add all components
pnpm dlx shadcn-svelte@latest add --all

# View all available components
pnpm dlx shadcn-svelte@latest list

Components install to: src/lib/components/ui/[component-name]/

Common Workflows

Basic Component Usage

<script lang="ts">
  import { Button } from "$lib/components/ui/button";
</script>

<Button variant="default">Click me</Button>
<Button variant="outline">Outlined</Button>
<Button variant="destructive">Delete</Button>
<Button disabled>Disabled</Button>

Form with Validation

pnpm dlx shadcn-svelte@latest add form input label
<script lang="ts">
  import { superForm } from "sveltekit-superforms";
  import { zodClient } from "sveltekit-superforms/adapters";
  import { z } from "zod";
  import * as Form from "$lib/components/ui/form";
  import { Input } from "$lib/components/ui/input";
  import { Button } from "$lib/components/ui/button";

  const schema = z.object({
    email: z.string().email(),
    name: z.string().min(2),
  });

  const form = superForm(data.form, {
    validators: zodClient(schema),
  });

  const { form: formData, enhance } = form;
</script>

<form method="POST" use:enhance>
  <Form.Field {form} name="email">
    <Form.Control let:attrs>
      <Form.Label>Email</Form.Label>
      <Input {...attrs} type="email" bind:value={$formData.email} />
    </Form.Control>
    <Form.FieldErrors />
  </Form.Field>

  <Button type="submit">Submit</Button>
</form>

Data Table with TanStack Table v8

For production data tables, use TanStack Table v8 (not svelte-headless-table) for advanced features like sorting, filtering, pagination, and row selection.

Installation
# Add table components and helpers
pnpm dlx shadcn-svelte@latest add table data-table button dropdown-menu checkbox input

# Install TanStack Table core
pnpm add @tanstack/table-core
Project Structure for Data Tables
routes/your-route/
  columns.ts                          # Column definitions
  data-table.svelte                   # Main table component
  data-table-actions.svelte           # Row action menus
  data-table-checkbox.svelte          # Selection checkboxes
  data-table-[field]-button.svelte    # Sortable headers
  +page.svelte                        # Page using the table
Basic Data Table Setup

Step 1: Define Columns (columns.ts)

import type { ColumnDef } from "@tanstack/table-core";
import { renderComponent, renderSnippet } from "$lib/components/ui/data-table/index.js";
import { createRawSnippet } from "svelte";

export type Payment = {
  id: string;
  amount: number;
  status: "pending" | "processing" | "success" | "failed";
  email: string;
};

export const columns: ColumnDef<Payment>[] = [
  // Simple text column
  {
    accessorKey: "status",
    header: "Status",
  },

  // Formatted cell with snippet
  {
    accessorKey: "amount",
    header: () => {
      const snippet = createRawSnippet(() => ({
        render: () => `<div class="text-end">Amount</div>`,
      }));
      return renderSnippet(snippet);
    },
    cell: ({ row }) => {
      const snippet = createRawSnippet<[{ value: number }]>((getValue) => {
        const { value } = getValue();
        const formatted = new Intl.NumberFormat("en-US", {
          style: "currency",
          currency: "USD",
        }).format(value);
        return {
          render: () => `<div class="text-end font-medium">${formatted}</div>`,
        };
      });
      return renderSnippet(snippet, { value: row.original.amount });
    },
  },

  // Component-based cell (for complex UI like action menus)
  {
    id: "actions",
    cell: ({ row }) => renderComponent(DataTableActions, { payment: row.original }),
  },
];

Step 2: Create Table Component (data-table.svelte)

<script lang="ts" generics="TData, TValue">
  import {
    type ColumnDef,
    type PaginationState,
    type SortingState,
    getCoreRowModel,
    getPaginationRowModel,
    getSortedRowModel,
  } from "@tanstack/table-core";
  import { createSvelteTable, FlexRender } from "$lib/components/ui/data-table/index.js";
  import * as Table from "$lib/components/ui/table/index.js";
  import { Button } from "$lib/components/ui/button/index.js";

  type DataTableProps<TData, TValue> = {
    data: TData[];
    columns: ColumnDef<TData, TValue>[];
  };

  let { data, columns }: DataTableProps<TData, TValue> = $props();

  // State management with Svelte 5 runes
  let pagination = $state<PaginationState>({ pageIndex: 0, pageSize: 10 });
  let sorting = $state<SortingState>([]);

  const table = createSvelteTable({
    get data() { return data; },
    columns,
    state: {
      get pagination() { return pagination; },
      get sorting() { return sorting; },
    },
    onPaginationChange: (updater) => {
      pagination = typeof updater === "function" ? updater(pagination) : updater;
    },
    onSortingChange: (updater) => {
      sorting = typeof updater === "function" ? updater(sorting) : updater;
    },
    getCoreRowModel: getCoreRowModel(),
    getPaginationRowModel: getPaginationRowModel(),
    getSortedRowModel: getSortedRowModel(),
  });
</script>

<div class="w-full">
  <div class="rounded-md border">
    <Table.Root>
      <Table.Header>
        {#each table.getHeaderGroups() as headerGroup (headerGroup.id)}
          <Table.Row>
            {#each headerGroup.headers as header (header.id)}
              <Table.Head>
                {#if !header.isPlaceholder}
                  <FlexRender
                    content={header.column.columnDef.header}
                    context={header.getContext()}
                  />
                {/if}
              </Table.Head>
            {/each}
          </Table.Row>
        {/each}
      </Table.Header>
      <Table.Body>
        {#each table.getRowModel().rows as row (row.id)}
          <Table.Row>
            {#each row.getVisibleCells() as cell (cell.id)}
              <Table.Cell>
                <FlexRender
                  content={cell.column.columnDef.cell}
                  context={cell.getContext()}
                />
              </Table.Cell>
            {/each}
          </Table.Row>
        {:else}
          <Table.Row>
            <Table.Cell colspan={columns.length} class="h-24 text-center">
              No results.
            </Table.Cell>
          </Table.Row>
        {/each}
      </Table.Body>
    </Table.Root>
  </div>

  <!-- Pagination controls -->
  <div class="flex items-center justify-end space-x-2 pt-4">
    <Button
      variant="outline"
      size="sm"
      onclick={() => table.previousPage()}
      disabled={!table.getCanPreviousPage()}
    >
      Previous
    </Button>
    <Button
      variant="outline"
      size="sm"
      onclick={() => table.nextPage()}
      disabled={!table.getCanNextPage()}
    >
      Next
    </Button>
  </div>
</div>

Step 3: Use in Page (+page.svelte)

<script lang="ts">
  import DataTable from "./data-table.svelte";
  import { columns } from "./columns.js";

  let { data } = $props();
</script>

<DataTable data={data.payments} {columns} />
Adding Sorting to Columns

Create sortable header button component (data-table-email-button.svelte):

<script lang="ts">
  import type { ComponentProps } from "svelte";
  import ArrowUpDownIcon from "@lucide/svelte/icons/arrow-up-down";
  import { Button } from "$lib/components/ui/button/index.js";

  let { variant = "ghost", ...restProps }: ComponentProps<typeof Button> = $props();
</script>

<Button {variant} {...restProps}>
  Email
  <ArrowUpDownIcon class="ms-2" />
</Button>

Update column definition:

{
  accessorKey: "email",
  header: ({ column }) => renderComponent(DataTableEmailButton, {
    onclick: column.getToggleSortingHandler(),
  }),
}
Adding Filtering

Add to data-table.svelte:

<script lang="ts" generics="TData, TValue">
  import {
    type ColumnFiltersState,
    getFilteredRowModel,
  } from "@tanstack/table-core";
  import { Input } from "$lib/components/ui/input/index.js";

  let columnFilters = $state<ColumnFiltersState>([]);

  const table = createSvelteTable({
    // ... existing config
    state: {
      get columnFilters() { return columnFilters; },
    },
    onColumnFiltersChange: (updater) => {
      columnFilters = typeof updater === "function" ? updater(columnFilters) : updater;
    },
    getFilteredRowModel: getFilteredRowModel(),
  });
</script>

<!-- Add above table -->
<div class="flex items-center py-4">
  <Input
    placeholder="Filter emails..."
    value={(table.getColumn("email")?.getFilterValue() as string) ?? ""}
    oninput={(e) => table.getColumn("email")?.setFilterValue(e.currentTarget.value)}
    onchange={(e) => table.getColumn("email")?.setFilterValue(e.currentTarget.value)}
    class="max-w-sm"
  />
</div>
Adding Row Selection

Create checkbox component (data-table-checkbox.svelte):

<script lang="ts">
  import type { ComponentProps } from "svelte";
  import { Checkbox } from "$lib/components/ui/checkbox/index.js";

  let {
    checked = false,
    onCheckedChange = (v) => (checked = v),
    ...restProps
  }: ComponentProps<typeof Checkbox> = $props();
</script>

<Checkbox bind:checked={() => checked, onCheckedChange} {...restProps} />

Add select column to columns.ts:

{
  id: "select",
  header: ({ table }) => renderComponent(DataTableCheckbox, {
    checked: table.getIsAllPageRowsSelected(),
    indeterminate: table.getIsSomePageRowsSelected() && !table.getIsAllPageRowsSelected(),
    onCheckedChange: (value) => table.toggleAllPageRowsSelected(!!value),
    "aria-label": "Select all",
  }),
  cell: ({ row }) => renderComponent(DataTableCheckbox, {
    checked: row.getIsSelected(),
    onCheckedChange: (value) => row.toggleSelected(!!value),
    "aria-label": "Select row",
  }),
  enableSorting: false,
  enableHiding: false,
}

Add to data-table.svelte:

<script lang="ts" generics="TData, TValue">
  import { type RowSelectionState } from "@tanstack/table-core";

  let rowSelection = $state<RowSelectionState>({});

  const table = createSvelteTable({
    // ... existing config
    state: {
      get rowSelection() { return rowSelection; },
    },
    onRowSelectionChange: (updater) => {
      rowSelection = typeof updater === "function" ? updater(rowSelection) : updater;
    },
  });
</script>

<!-- Show selection count -->
<div class="text-muted-foreground flex-1 text-sm">
  {table.getFilteredSelectedRowModel().rows.length} of{" "}
  {table.getFilteredRowModel().rows.length} row(s) selected.
</div>
Row Actions Pattern

Create actions component (data-table-actions.svelte):

<script lang="ts">
  import EllipsisIcon from "@lucide/svelte/icons/ellipsis";
  import { Button } from "$lib/components/ui/button/index.js";
  import * as DropdownMenu from "$lib/components/ui/dropdown-menu/index.js";

  let { id }: { id: string } = $props();
</script>

<DropdownMenu.Root>
  <DropdownMenu.Trigger>
    {#snippet child({ props })}
      <Button {...props} variant="ghost" size="icon" class="relative size-8 p-0">
        <span class="sr-only">Open menu</span>
        <EllipsisIcon />
      </Button>
    {/snippet}
  </DropdownMenu.Trigger>
  <DropdownMenu.Content>
    <DropdownMenu.Label>Actions</DropdownMenu.Label>
    <DropdownMenu.Item onclick={() => navigator.clipboard.writeText(id)}>
      Copy ID
    </DropdownMenu.Item>
    <DropdownMenu.Separator />
    <DropdownMenu.Item>View details</DropdownMenu.Item>
    <DropdownMenu.Item>Edit</DropdownMenu.Item>
  </DropdownMenu.Content>
</DropdownMenu.Root>
Styling Data Tables with Tailwind v4.1

Define CSS Variables for Table States in src/app.css:

@import "tailwindcss";

@layer theme {
  :root {
    /* Table colors */
    --color-table-bg: 0 0% 100%;
    --color-table-row-hover: 0 0% 96.1%;
    --color-table-row-selected: 210 40% 96%;
    --color-table-border: 0 0% 89.8%;
    --color-table-text: 0 0% 3.6%;
    --color-table-header-bg: 0 0% 94.1%;
  }

  .dark {
    --color-table-bg: 0 0% 14.9%;
    --color-table-row-hover: 0 0% 22%;
    --color-table-row-selected: 210 100% 35%;
    --color-table-border: 0 0% 22%;
    --color-table-text: 0 0% 98%;
    --color-table-header-bg: 0 0% 22%;
  }
}

@layer utilities {
  .table-cell {
    @apply px-4 py-3 text-sm;
  }

  .table-row-hover {
    @apply hover:bg-[hsl(var(--color-table-row-hover))] transition-colors;
  }

  .table-row-selected {
    @apply bg-[hsl(var(--color-table-row-selected))] border-l-4 border-l-primary;
  }

  .table-header {
    @apply bg-[hsl(var(--color-table-header-bg))] font-semibold text-xs uppercase tracking-wide;
  }
}

Apply Row States in your table component:

<Table.Body>
  {#each table.getRowModel().rows as row (row.id)}
    {@const rowSelected = row.getIsSelected()}
    <Table.Row
      class={cn(
        "table-row-hover",
        rowSelected && "table-row-selected"
      )}
      data-state={rowSelected && "selected"}
    >
      {#each row.getVisibleCells() as cell (cell.id)}
        <Table.Cell class="table-cell">
          <FlexRender
            content={cell.column.columnDef.cell}
            context={cell.getContext()}
          />
        </Table.Cell>
      {/each}
    </Table.Row>
  {/each}
</Table.Body>
Key Patterns for TanStack Tables
  1. Svelte 5 State Management: Always use $state and get accessors
  2. State Updater Pattern: All handlers follow (updater) => state = typeof updater === "function"? updater(state): updater
  3. Cell Rendering:

- Simple HTML: createRawSnippet → renderSnippet - Components: renderComponent for interactive UI - Plain text: Direct string or number

  1. Row Models: Add the appropriate row model for each feature (pagination, sorting, filtering)
Common Pitfalls
  • Forgetting get accessors in createSvelteTable state config
  • Not binding both oninput and onchange for filter inputs
  • Missing row models (e.g., getFilteredRowModel for filtering)
  • Using wrong import path for data-table helpers

For comprehensive DataTable reference including:

  • Advanced sorting and filtering patterns
  • Column visibility controls
  • Responsive table layouts
  • Performance optimization (virtual scrolling, debouncing)
  • Complete working examples with all features

See: shadcn-datatable.md and datatable-tanstack-svelte5.md reference documents

Modal/Dialog

pnpm dlx shadcn-svelte@latest add dialog button
<script lang="ts">
  import * as Dialog from "$lib/components/ui/dialog";
  import { Button } from "$lib/components/ui/button";

  let open = false;
</script>

<Dialog.Root bind:open>
  <Dialog.Trigger asChild let:builder>
    <Button builders={[builder]}>Open Dialog</Button>
  </Dialog.Trigger>
  <Dialog.Content>
    <Dialog.Header>
      <Dialog.Title>Dialog Title</Dialog.Title>
      <Dialog.Description>This is a dialog.</Dialog.Description>
    </Dialog.Header>
    <p>Your content here</p>
    <Dialog.Footer>
      <Button on:click={() => (open = false)}>Close</Button>
    </Dialog.Footer>
  </Dialog.Content>
</Dialog.Root>

Drawer (Mobile-Friendly Sidebar)

pnpm dlx shadcn-svelte@latest add drawer button
<script lang="ts">
  import * as Drawer from "$lib/components/ui/drawer";
  import { Button } from "$lib/components/ui/button";

  let open = false;
</script>

<Drawer.Root bind:open>
  <Drawer.Trigger asChild let:builder>
    <Button builders={[builder]} variant="outline">Open Drawer</Button>
  </Drawer.Trigger>
  <Drawer.Content>
    <Drawer.Header>
      <Drawer.Title>Navigation</Drawer.Title>
    </Drawer.Header>
    <nav class="flex flex-col gap-2 p-4">
      <a href="/">Home</a>
      <a href="/about">About</a>
    </nav>
    <Drawer.Footer>
      <Drawer.Close asChild let:builder>
        <Button builders={[builder]} variant="outline">Close</Button>
      </Drawer.Close>
    </Drawer.Footer>
  </Drawer.Content>
</Drawer.Root>

Component Organization

Project Structure

src/
├── lib/
│   ├── components/
│   │   ├── ui/              (shadcn-svelte components)
│   │   │   ├── button/
│   │   │   ├── card/
│   │   │   ├── dialog/
│   │   │   └── [...]
│   │   └── custom/          (your custom components)
│   │       └── header.svelte
│   └── utils/
│       └── cn.ts            (class utility from init)
└── routes/

Import Patterns

// Named imports (preferred for tree-shaking)
import { Button } from "$lib/components/ui/button";
import { Dialog, DialogTrigger, DialogContent } from "$lib/components/ui/dialog";

// Namespace imports
import * as Button from "$lib/components/ui/button";
import * as Dialog from "$lib/components/ui/dialog";

Customization

Theme via CSS Variables (Tailwind v4.1)

Edit src/app.css to define theme colors as CSS variables. Tailwind v4.1 auto-scans these:

@import "tailwindcss";

@layer theme {
  :root {
    --color-background: 0 0% 100%;
    --color-foreground: 0 0% 3.6%;
    --color-primary: 0 0% 9%;
    --color-primary-foreground: 0 0% 100%;
    --color-secondary: 0 0% 96.1%;
    --color-secondary-foreground: 0 0% 9%;
    --color-destructive: 0 84% 60%;
    --color-muted: 0 0% 96.1%;
    --color-muted-foreground: 0 0% 45.1%;
    --color-border: 0 0% 89.8%;
  }

  .dark {
    --color-background: 0 0% 3.6%;
    --color-foreground: 0 0% 98%;
    --color-primary: 0 0% 98%;
    --color-primary-foreground: 0 0% 9%;
    --color-secondary: 0 0% 14.9%;
    --color-secondary-foreground: 0 0% 98%;
    --color-destructive: 0 84% 60%;
    --color-muted: 0 0% 14.9%;
    --color-muted-foreground: 0 0% 63.9%;
    --color-border: 0 0% 14.9%;
  }
}

@layer utilities {
  .btn-custom {
    @apply px-4 py-2 rounded-lg font-semibold transition-colors;
  }
}

Reference in tailwind.config.js (if needed):

export default {
  theme: {
    colors: {
      background: 'hsl(var(--color-background))',
      foreground: 'hsl(var(--color-foreground))',
      primary: 'hsl(var(--color-primary))',
      'primary-foreground': 'hsl(var(--color-primary-foreground))',
      // ... map CSS variables to theme
    },
    extend: {
      spacing: {
        gutter: '1rem',
      },
    },
  },
}

Override Component Styles

Modify components in src/lib/components/ui/[name]/ directly. Tailwind v4.1 automatically applies classes:

<!-- src/lib/components/ui/button/button.svelte -->
<script lang="ts">
  import { cn } from "$lib/utils";

  interface Props {
    variant?: "default" | "outline" | "ghost";
    size?: "sm" | "md" | "lg";
    class?: string;
  }

  let { variant = "default", size = "md", class: className }: Props = $props();

  const baseClasses = cn(
    "inline-flex items-center justify-center font-semibold transition-colors",
    {
      "bg-primary text-primary-foreground hover:bg-primary/90": variant === "default",
      "border border-border bg-background hover:bg-muted": variant === "outline",
      "hover:bg-muted": variant === "ghost",
    },
    {
      "h-8 px-3 text-xs": size === "sm",
      "h-10 px-4 text-sm": size === "md",
      "h-12 px-6 text-base": size === "lg",
    },
    className
  );
</script>

<button class={baseClasses}>
  <slot />
</button>

Tailwind v4.1 Content Scanning

No manual content paths needed—Tailwind v4.1 auto-scans your SvelteKit project:

// tailwind.config.js (minimal, Vite handles scanning)
export default {
  theme: {
    extend: {
      colors: {
        brand: {
          50: '#f9fafb',
          600: '#1f2937',
        },
      },
    },
  },
}

For custom @source directive in CSS:

@import "tailwindcss";

@source "../src/lib/components";

Key Dependencies

Automatically installed with init and Tailwind v4.1:

PackagePurpose
@tailwindcss/viteVite plugin for zero-runtime CSS with v4.1
tailwindcssTailwind CSS framework (v4.1+)
clsx / tailwind-mergeClass utility functions via cn()
@lucide/svelteIcon library (650+ icons)
bits-uiHeadless UI primitives (accessibility)
sveltekitFull-stack framework
viteBuild tool (handles CSS imports)

Not needed in v4.1:

  • PostCSS
  • Autoprefixer
  • tailwind.config.ts for basic projects

Advanced Topics

Dark Mode

Use mode-watcher for automatic dark mode switching:

pnpm i mode-watcher
<script lang="ts">
  import { modeWatcher } from "mode-watcher";
</script>

<div use:modeWatcher>
  <!-- Your app content -->
</div>

Icons with Lucide

pnpm dlx shadcn-svelte@latest add button
<script lang="ts">
  import { Button } from "$lib/components/ui/button";
  import { Heart } from "@lucide/svelte";
</script>

<Button>
  <Heart class="w-4 h-4 mr-2" />
  Save
</Button>

Creating Custom Components

Copy shadcn component structure as template:

<!-- src/lib/components/custom/my-card.svelte -->
<script lang="ts">
  import { cn } from "$lib/utils";

  interface Props {
    title: string;
    class?: string;
  }

  let { title, class: className, children }: Props & { children?: any } = $props();
</script>

<div class={cn("rounded-lg border p-4", className)}>
  <h3>{title}</h3>
  {#if children}
    <slot />
  {/if}
</div>

Building Component Registries

To create a custom registry for sharing components:

// registry.json
{
  "$schema": "https://shadcn-svelte.com/schema/registry.json",
  "name": "my-components",
  "homepage": "https://my-components.com",
  "items": [
    {
      "name": "custom-card",
      "type": "registry:component",
      "title": "Custom Card",
      "description": "Extended card component",
      "files": [
        {
          "path": "./src/lib/custom-card.svelte",
          "type": "registry:component"
        }
      ]
    }
  ]
}

Build registry: pnpm run registry:build

Troubleshooting

Component Not Found

Verify install location: src/lib/components/ui/[component]/

pnpm dlx shadcn-svelte@latest list    # Check installed components
pnpm dlx shadcn-svelte@latest add button --overwrite  # Reinstall

Styling Issues

  1. Ensure Tailwind CSS is configured in tailwind.config.ts
  2. Check that CSS variables are defined in src/app.css
  3. Verify component imports use correct path aliases

TypeScript Errors

Update TypeScript settings in svelte.config.js:

const config: Config = {
  kit: {
    alias: {
      "$lib": "./src/lib",
      "$components": "./src/lib/components",
    },
  },
};

Command and Hook

/shadcn Command

Interactive assistant for shadcn-svelte component development:

/shadcn              # Show help and available topics
/shadcn add          # Component installation guidance
/shadcn form         # Form patterns with superforms
/shadcn table        # DataTable with TanStack Table v8
/shadcn dialog       # Modal/drawer/sheet patterns
/shadcn theme        # CSS variables and customization
/shadcn debug        # Troubleshooting common issues
/shadcn button       # Specific component guidance

Development Hook

A hook is available that triggers when editing files in $lib/components/ui/:

Install hook script:

# Script location: ~/.claude/hooks/shadcn-component-reminder.sh
chmod +x ~/.claude/hooks/shadcn-component-reminder.sh

Add to ~/.claude/settings.json:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "~/.claude/hooks/shadcn-component-reminder.sh",
            "timeout": 5
          }
        ]
      }
    ]
  }
}

The hook provides contextual reminders about shadcn patterns when editing component files.

Resources

Summary

shadcn-svelte provides production-grade UI components that you control. Start with init, add components via CLI, customize in-place, and build accessible applications with TypeScript and Tailwind. The copy-paste model means you own your UI layer—no library lock-in.

平台分布

Claude Code

28.8%
按下载量换算21

OpenCode

27.1%
按下载量换算20

Antigravity

17.57%
按下载量换算13

windsurf

11.82%
按下载量换算9

Gemini CLI

8.35%
按下载量换算6

Codex

3.44%
按下载量换算3

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。

继续浏览同类 Skills