---
slug: "svelte-headless-ui-library-2025"
title: "SvelteKit + Tailwind で使えるHeadless UIライブラリ 2025"
description: "Svelte で使える Headless UI ライブラリを調べてまとめました。"
url: "https://www.ytyng.com/blog/svelte-headless-ui-library-2025"
publish_date: "2025-08-30T04:18:22Z"
created: "2025-08-30T04:18:22.927Z"
updated: "2026-02-27T11:10:43.489Z"
categories: ["Svelte"]
keywords: ""
featured_image_url: "https://media.ytyng.com/resize/20251018/b86efb0277664385ae91d1787974499e.png.webp?width=768"
has_video: true
has_music: true
video_urls: ["https://media.ytyng.net/ytyng-blog/326/featured-video-1.mp4", "https://media.ytyng.net/ytyng-blog/326/featured-video-2.mp4", "https://media.ytyng.net/ytyng-blog/326/featured-video-3.mp4"]
music_urls: ["https://media.ytyng.net/ytyng-blog/326/featured-music-326-1.mp3", "https://media.ytyng.net/ytyng-blog/326/featured-music-326-2.mp3"]
lang: "ja"
---

# SvelteKit + Tailwind で使えるHeadless UIライブラリ 2025

## はじめに

SvelteKitでアプリケーションを開発していると、「アクセシブルで美しいUIコンポーネントが欲しいけれど、デザインの自由度は保ちたい」という悩みに直面します。そんな時に威力を発揮するのがHeadless UIライブラリです。

この記事では、SvelteKit + Tailwind環境で使用できる主要なHeadless UIライブラリを徹底比較し、プロジェクトの要件に応じた最適な選択ができるよう解説します。実際の導入手順から注意点、運用のコツまで実務に直結する内容をお届けします。

**この記事で分かること：**
- 4つの主要Headless UIライブラリの特徴と違い
- プロジェクト要件別の選定フローチャート
- 実装時の注意点とベストプラクティス
- SSR対応やアクセシビリティの考慮点

## Headless UIライブラリとは？

Headless UIライブラリは、**ロジックとアクセシビリティ機能を提供し、スタイリングは開発者に委ねる**コンポーネントライブラリです。従来のUIライブラリと異なり、見た目が決まっていないため、独自のデザインシステムを構築しながらも、複雑なインタラクションやアクセシビリティ要件をライブラリに任せることができます。

## SvelteKit対応の主要4ライブラリ

### 1. Melt UI - Builder APIの最高峰

**公式サイト：** [https://next.melt-ui.com/guides/installation](https://next.melt-ui.com/guides/installation)  
**GitHub：** [https://github.com/melt-ui/melt-ui](https://github.com/melt-ui/melt-ui)

Melt UIは、Svelte向けHeadless UIライブラリの中で最も低レベルなAPIを提供します。Builder APIパターンを採用し、開発者に最大限の制御権を与えます。

各コンポーネントは、 スクリプトで書く Builder パターンと、HTML構造で書く Component パターンの2通りの書き方ができます。

後述の Bits UI では Builder パターンでは書かないため、 Builder パターンを使いたい場合はこちらになると思います。

しかし、コンポーネント数は多くはありません。

```javascript
// Melt UI の Builder API 例
import { createCollapsible, melt } from '@melt-ui/svelte'

const { 
  elements: { root, content, trigger }, 
  states: { open } 
} = createCollapsible()
```

**特徴：**
- WAI-ARIAに準拠したアクセシビリティ実装
- 柔軟性が高く、あらゆるカスタマイズに対応
- TypeScript完全対応
- SSR/SvelteKit対応

**適用場面：**
- 高度なカスタマイズ要件がある
- 独自のデザインシステムを構築したい
- チームに設計力がある

**導入方法：**
```bash
npm install melt
```

### 2. Bits UI - バランス型の実用派

**公式サイト：** [https://bits-ui.com/](https://bits-ui.com/)  
**GitHub：** [https://github.com/huntabyte/bits-ui](https://github.com/huntabyte/bits-ui)

Bits UIは、Melt UIを基盤としながらも、より使いやすいコンポーネントAPIを提供します。React/Vueに慣れた開発者にとって親しみやすい設計となっています。

提供しているコンポーネント数が Melt UI より多いため、より広範囲の用途をカバーでき、まず最初はこちらを使うのが良いと思います。

しかし、Melt UI に含まれている Toast や File Upload は含まれていないため、自作するか他のライブラリを使うことになります。

逆に、 Toast は [Svelte Sonner](https://svelte-sonner.vercel.app) を使う、という場合はちょうどよいと思います。

```javascript
// Bits UI のComponent API 例
<script>
  let value = null
</script>

<Select.Root bind:value>
  <Select.Trigger>
    <Select.Value placeholder="Select a fruit" />
  </Select.Trigger>
  <Select.Content>
    {#each fruits as fruit}
      <Select.Item value={fruit.value}>
        <Select.ItemIndicator />
        <Select.ItemText>{fruit.label}</Select.ItemText>
      </Select.Item>
    {/each}
  </Select.Content>
</Select.Root>
```

**特徴：**
- Melt UIの安定性とコンポーネントの使いやすさを両立
- 豊富なコンポーネントライブラリ
- shadcn-svelteの基盤
- 学習コストが低い

**適用場面：**
- バランスの取れたソリューションが欲しい
- チーム開発で統一感を保ちたい
- React/Vue経験者が多い

**導入方法：**
```bash
npm install bits-ui
```

### 3. Svelte Headless UI - 移行の架け橋

**公式サイト：** [https://svelte-headlessui.goss.io/docs/2.0](https://svelte-headlessui.goss.io/docs/2.0)  
**GitHub：** [https://github.com/rgossiaux/svelte-headlessui](https://github.com/rgossiaux/svelte-headlessui)

React/VueのHeadless UIライブラリをSvelteに移植したコミュニティプロジェクトです。既存のHeadless UI経験者には馴染みやすいAPIを提供します。

**特徴：**
- Tailwind Labs公式ではないコミュニティ実装
- 主要コンポーネント（Dialog、Menu、Popover等）を約10個提供
- Tailwind UIパターンとの親和性が高い
- React/VueからSvelteへの移行時に有用

**注意点：**
- コンポーネント数は限定的
- Tailwind UIのサンプルはそのまま使用できず調整が必要

**適用場面：**
- React/Vue Headless UI経験者
- Tailwind UIを活用したい
- 限定的なコンポーネント要求

**導入方法：**
```bash
npm install @rgossiaux/svelte-headlessui
```

### 4. shadcn-svelte - コピペ式の新発想

**公式サイト：** [https://www.shadcn-svelte.com/](https://www.shadcn-svelte.com/)  
**GitHub：** [https://github.com/huntabyte/shadcn-svelte](https://github.com/huntabyte/shadcn-svelte)

shadcn-svelteは従来のライブラリとは異なり、**コンポーネントのコードを直接プロジェクトに生成・コピーする**システムです。

**特徴：**
- ライブラリではなく、生成コードを自プロジェクトに配置
- Bits UI + Tailwindをベースとした美しいデザイン
- CLI使用で簡単導入
- 自由度が極めて高い
- アップデートは手動取り込みが基本

**適用場面：**
- 最短でプロダクション品質のUIが欲しい
- デザインシステムを構築したい
- 生成されたコードの保守を自分で管理できる

**導入方法：**
```bash
npx shadcn-svelte@latest init
npx shadcn-svelte@latest add button
```

## プロジェクト要件別選定フローチャート

```
プロジェクトの要件は？
    ↓
最短でプロダクション品質 → shadcn-svelte
    ↓
バランスの取れたソリューション → Bits UI
    ↓
最大限のカスタマイズ自由度 → Melt UI
    ↓
既存Headless UI APIに慣れている → Svelte Headless UI
```

## ライブラリ機能比較表

| 項目 | Melt UI | Bits UI | Svelte Headless UI | shadcn-svelte |
|------|---------|---------|-------------------|---------------|
| **Svelte 5対応** | ✅ | ✅ | ⚠️ 一部 | ✅ |
| **SSRサポート** | ✅ | ✅ | ✅ | ✅ |
| **コンポーネント数** | 25+ | 30+ | ~10 | 40+ |
| **学習コスト** | 高 | 中 | 中 | 低 |
| **カスタマイズ性** | 最高 | 高 | 中 | 高 |
| **TypeScript対応** | 完全 | 完全 | 完全 | 完全 |
| **位置決め** | floating-ui | floating-ui | 独自 | floating-ui |
| **アップデート** | npm | npm | npm | 手動 |
| **メンテ体制** | 活発 | 活発 | 個人 | 活発 |

## よくある質問（FAQ）

### Melt UI と Bits UI の違いは？
Melt UIは低レベルなBuilder API、Bits UIはそれをラップしたComponent APIを提供します。Bits UIの方が学習コストは低く、Melt UIの方がカスタマイズ性に優れます。

### shadcn-svelteは商用プロジェクトで使用できますか？
はい、MITライセンスで提供されており、商用利用可能です。ただし生成されたコードは自分のプロジェクトの一部となるため、保守は自己責任となります。

### Svelte 5で使用する際の注意点は？
Melt UIとBits UIはSvelte 5のrunes（`$state`、`$derived`等）に対応していますが、Svelte Headless UIは一部対応が不完全な場合があります。プロジェクトのSvelteバージョンと各ライブラリの対応状況を事前に確認してください。

### SSRでDialog/Popoverを使用する際の注意点は？
- サーバー側では閉じた状態のHTMLのみを生成
- `data-state="closed"`で初期スタイルを制御
- クライアントサイドでのハイドレーション完了後にポータル機能を有効化
- スクロールロック時のレイアウトシフト対策（body余白調整）が必要

## アクセシビリティチェックリスト

### Dialog コンポーネント
- [ ] Escキーで閉じられる
- [ ] 開いた時に適切な要素にフォーカス
- [ ] フォーカストラップが機能する
- [ ] 閉じた時に元の要素にフォーカス復帰
- [ ] `aria-labelledby`と`aria-describedby`が適切に設定

### Menu/Select コンポーネント
- [ ] 矢印キーで項目間を移動可能
- [ ] Typeahead（文字入力で項目移動）が機能
- [ ] Home/Endキーで最初/最後の項目に移動
- [ ] 適切なARIAロール（`menu`、`menuitem`等）が設定
- [ ] スクリーンリーダーで適切に読み上げ

### 共通チェック項目
- [ ] `prefers-reduced-motion`に対応したアニメーション
- [ ] キーボードのみでの操作が可能
- [ ] 色のみに頼らない情報伝達
- [ ] 適切なコントラスト比の確保

## 実務での注意点とベストプラクティス

### Svelteバージョン対応

各ライブラリのSvelte 4/5対応状況は異なります。プロジェクト開始前に必ず対応バージョンを確認し、整合性を保ちましょう。

### SSR/SvelteKit環境での配慮

Dialog、Popover等のコンポーネントはDOM操作を伴うため、SSR環境では以下の点に注意が必要です：

- ポータル機能とフォーカストラップはクライアント側で有効化される
- `onMount`前提の処理とSSR時の条件分岐を適切に実装
- 初期表示時のレイアウトシフトやチラつきを最小限に

### よくある実装の落とし穴

**Z-index設計**
```css
/* ポータル先の指定を明確に */
.modal-overlay { z-index: 50; }
.modal-content { z-index: 51; }
```

**フォーム連携**
```javascript
// Svelte 5 (runes使用)
let formData = $state({
  email: '',
  notifications: false
})

// Svelte 4 (従来の書き方)
import { writable } from 'svelte/store'
const formData = writable({
  email: '',
  notifications: false
})
```

**アニメーション実装**
Headless UIライブラリ自体にはアニメーションは含まれていません。SvelteのtransitionやTailwindのアニメーション機能を組み合わせる必要があります。

## パフォーマンスと保守性の考慮

### バンドルサイズ比較

- **Melt UI**: 軽量（必要な機能のみインポート可能）
- **Bits UI**: 中程度（Melt UI + ラッパー層）
- **Svelte Headless UI**: 軽量（コンポーネント数が限定的）
- **shadcn-svelte**: プロジェクト依存（使用するコンポーネントのみ）

### メンテナンス戦略

**定期的な更新確認**
- ライブラリの更新頻度とBreaking Changeの履歴を把握
- 特にshadcn-svelteは手動更新のため、定期的な差分チェックが必要

**テスト戦略**
- Axe-coreやPlaywrightを使用したアクセシビリティテスト
- キーボード操作の回帰テスト
- SSR環境での動作確認

## 実装サンプル集

### Melt UI でのDialog実装

```javascript
<script>
  import { createDialog, melt } from '@melt-ui/svelte'
  
  const {
    elements: { root, trigger, overlay, content, title, description, close },
    states: { open }
  } = createDialog()
</script>

<div use:melt={$root}>
  <button use:melt={$trigger}>Open Dialog</button>

  {#if $open}
    <div use:melt={$overlay} class="fixed inset-0 bg-black/50" />
    <div use:melt={$content} class="fixed inset-0 flex items-center justify-center">
      <div class="bg-white p-6 rounded-lg">
        <h2 use:melt={$title} class="text-lg font-semibold">Dialog Title</h2>
        <p use:melt={$description} class="mt-2 text-gray-600">
          Dialog description goes here.
        </p>
        <button use:melt={$close} class="mt-4 px-4 py-2 bg-blue-500 text-white rounded">
          Close
        </button>
      </div>
    </div>
  {/if}
</div>
```

**注意点：**
- SSR環境では初期状態で`data-state="closed"`を適用し、ハイドレーション完了まで適切な表示制御を
- Portal先の設定やスクロールロック機能はライブラリのオプションで調整可能

### Bits UI でのSelect実装

```javascript
<script>
  import { Select } from 'bits-ui'
  
  const fruits = [
    { value: 'apple', label: 'Apple' },
    { value: 'banana', label: 'Banana' },
    { value: 'orange', label: 'Orange' }
  ]
  
  let value = null
</script>

<Select.Root bind:value>
  <Select.Trigger class="flex items-center justify-between w-48 px-3 py-2 border rounded">
    <Select.Value placeholder="Select a fruit" />
    <Select.Icon class="ml-2" />
  </Select.Trigger>
  
  <Select.Content class="bg-white border rounded shadow-lg">
    {#each fruits as fruit}
      <Select.Item 
        value={fruit.value} 
        class="px-3 py-2 hover:bg-gray-100 cursor-pointer"
      >
        <Select.ItemIndicator />
        <Select.ItemText>{fruit.label}</Select.ItemText>
      </Select.Item>
    {/each}
  </Select.Content>
</Select.Root>
```

**注意点：** Bits UIはバージョンによってプロパティ名（`bind:value` vs `bind:selected`）が異なる場合があります。使用中のバージョンに対応したAPIを公式ドキュメントで確認してください。

## まとめ

SvelteKit + Tailwind環境でのHeadless UIライブラリ選択は、プロジェクトの要件、チームのスキル、長期的な保守戦略によって決まります。

**今すぐ始められるアクション：**
1. **今日中に**: 現在のプロジェクト要件を整理し、選定フローチャートで最適なライブラリを特定
2. **今週中に**: 選択したライブラリで簡単なプロトタイプを作成し、チームでの使用感を検証
3. **今月中に**: 本格導入前にSSR動作確認とアクセシビリティテストを実施

適切なライブラリ選択により、開発効率とユーザー体験の両方を大きく向上させることができます。まずは小さなコンポーネントから始めて、段階的に適用範囲を広げていくことをお勧めします。

## 参考リンク

- [Melt UI 公式ドキュメント](https://www.melt-ui.com/)
- [Bits UI 公式ドキュメント](https://bits-ui.com/)
- [Svelte Headless UI 公式ドキュメント](https://svelte-headlessui.goss.io/)
- [shadcn-svelte 公式サイト](https://www.shadcn-svelte.com/)
- [Tailwind UI](https://tailwindui.com/)
- [WAI-ARIA Authoring Practices Guide](https://www.w3.org/WAI/ARIA/apg/)
