2026.05.27 リリースしました

確認する

Header

Headerは、Webサイトやアプリケーションのページ上部に表示されるコンポーネントです。
ナビゲーションやメニューなどの主要な要素を表示します。

header/default is coming soon.

プロパティ

Headerは、以下のプロパティをサポートしています。

名前 デフォルト値 説明
desktopMenus GlobalNavigationItem[] [] PC用のメニューとして表示する値の配列です。
mobileMenus MenuItem[] [] SP用のメニューとして表示する値の配列です。
currentIndex number 現在選択されているメニューを示すハイライト用の数値です。
profileImgUrl string '' プロフィール画像のURLです。
placeholder string '' 検索窓のプレースホルダーです。

インストールの手順

以下のコンポーネントのコードを、使いたいプロジェクトにコピー&ペーストします。
パスは実際のプロジェクトの構成にあわせて更新します。

modules/Header.svelte
        <!--
@component
## 概要
- Header は、検索・ナビゲーション・プロフィール画像をひとまとめにしたレスポンシブヘッダーです。
PCではグローバルナビゲーション、SPではハンバーガー+ドロワーでメニューを表示し、渡した配列から項目を生成します。生成された項目(メニュー)ごとに追加でサブメニューを表示することができます。PCではスニペットを渡し、SPではmobileMenusのoptionsに値を書くことで、任意のサブメニューを表示可能です。

## 機能
- 渡した配列をそのままメニューとしてレンダリング
- 検索窓を表示
- プロフィール画像を表示。

## Props
- desktopMenus: PC時のメニュー。グローバルナビゲーションコンポーネントに渡す配列。省略可能で、省略した場合は項目が表示されない。
- mobileMenus: SP時(Drawer内)のメニュー。メニューコンポーネントに渡す配列。省略可能で、省略した場合は項目が表示されない。
- currentIndex: 現在表示中のページの位置を示すハイライト。省略可能で、省略した場合はハイライトが表示されない。
- profileImgUrl: 右上に表示するプロフィール画像URL。省略可能で、省略した場合はデフォルトの灰色アイコンになる。
- placeholder: 検索窓のプレースホルダー。省略可能で、省略した場合はプレースホルダーが表示されない。
- class: ヘッダー全体に付与する追加クラス。省略可能。
- desktopMenusChildren: PC時のサブメニュー用のスニペット。省略可能で、省略した場合はサブメニューが表示されない。

## Usage
```svelte
サブメニューがない場合
<Header {desktopMenus} {mobileMenus} {currentIndex} {profileImgUrl} {placeholder} />

サブメニューがある場合
<Header {desktopMenus} {mobileMenus} {currentIndex} {profileImgUrl} {placeholder}>
  {#snippet desktopMenusChildren(item)}
    {#if item.id === 'menu1'}
      PCサブメニュー1の要素が入ります。
    {/if}
    {#if item.id === 'menu2'}
      PCサブメニュー2の要素が入ります。
    {/if}
  {/snippet}
</Header>
```
-->

<script module lang="ts">
  import type { MenuItem } from '$lib/components/ui/atoms/Menu.svelte';
  import type { GlobalNavigationItem } from '$lib/components/ui/modules/GlobalNavigation.svelte';
  import type { Snippet } from 'svelte';
  import type { ClassValue } from 'svelte/elements';

  export interface HeaderProps {
    /** メニューとして表示する値の配列(PC用)。グローバルナビゲーションコンポーネント用 */
    desktopMenus?: GlobalNavigationItem[];
    /** メニューとして表示する値の配列(SP用)。メニューコンポーネント用 */
    mobileMenus?: MenuItem[];
    /** 現在選択されているメニューを示すハイライト用の数値 */
    currentIndex?: number;
    /** プロフィール画像のURL */
    profileImgUrl?: string;
    /** 検索窓のプレースホルダー */
    placeholder?: string;
    /** 追加クラス */
    class?: ClassValue;
    /** PC用のサブメニュー */
    desktopMenusChildren?: Snippet<[GlobalNavigationItem, number]>;
  }
</script>

<script lang="ts">
  import Button from '$lib/components/ui/atoms/Button.svelte';
  import Input from '$lib/components/ui/atoms/Input.svelte';
  import Menu from '$lib/components/ui/atoms/Menu.svelte';
  import Drawer from '$lib/components/ui/modules/Drawer.svelte';
  import GlobalNavigation from '$lib/components/ui/modules/GlobalNavigation.svelte';
  import Hamburger from '@lucide/svelte/icons/menu';
  import Search from '@lucide/svelte/icons/search';
  import UserRound from '@lucide/svelte/icons/user-round';
  import X from '@lucide/svelte/icons/x';

  let { desktopMenus = [], mobileMenus = [], currentIndex, profileImgUrl = '', placeholder = '', class: className, desktopMenusChildren }: HeaderProps = $props();

  /** レスポンシブ切り替えの境界値(この値を下回るとモバイル表示、以上でデスクトップ表示) */
  const RESPONSIVE_BREAKPOINT_PX = 768;

  let searchText = $state('');

  let isOpen = $state(false);

  let viewportWidth = $state<number>(0);

  $effect(() => {
    // SPからPCの幅に切り替わった場合、ドロワーを閉じる。
    if (viewportWidth >= RESPONSIVE_BREAKPOINT_PX) {
      isOpen = false;
    }
  });

  /**
   * ドロワーの開閉状態をトグルする。
   * @param event クリックイベント(バブリングを止める)
   */
  function openDrawer(event: MouseEvent): void {
    event.stopPropagation();
    isOpen = !isOpen;
  }
</script>

<header class={[className, 'relative z-10 flex items-center justify-between w-full h-14 px-6 after:absolute after:inset-x-0 after:bottom-0 after:content-[\'\'] max-md:h-16 after:h-px max-md:px-4 after:bg-border after:-z-10']} bind:clientWidth={viewportWidth}>
  <!-- メニュー(PC用) -->
  <div class="hidden h-full md:block">
    <GlobalNavigation class="h-full" menus={desktopMenus} {currentIndex}>
      {#snippet children(item, index)}
        {@render desktopMenusChildren?.(item, index)}
      {/snippet}
    </GlobalNavigation>
  </div>

  {#if mobileMenus?.length}
    <!-- ハンバーガーアイコン(SP) -->
    <div class="mr-4 md:hidden">
      <Button class="border border-border" type="button" variant="secondary" size="small" tone="solid" isSquare onclick={openDrawer}>
        <Hamburger size="1.125rem" />
      </Button>
    </div>

    <!-- ハンバーガーアイコンのクリック時に開くドロワー(SP) -->
    <Drawer class="md:hidden" direction="left" bind:isOpen>
      {#snippet children()}
        <div class="relative flex flex-col justify-between h-full px-4 pt-14">
          <Button class="absolute top-2 right-2" variant="secondary" size="small" tone="ghost" isSquare onclick={() => (isOpen = false)}><X size="1rem" /></Button>
          <!-- メニュー(SP用) -->
          <div class="h-full overflow-y-auto">
            {#each mobileMenus as menu, index}
              <Menu class="w-auto" item={menu} current={currentIndex === index ? menu.id : ''} />
            {/each}
          </div>
        </div>
      {/snippet}
    </Drawer>
  {/if}

  <div class="flex items-center shrink-0 gap-4 max-md:shrink max-md:w-full">
    <!-- 検索窓 -->
    <div class="w-75 max-md:w-full">
      <Input class="w-full" type="text" {placeholder} bind:value={searchText}>
        {#snippet startContent()}
          <Search class="text-muted-foreground pointer-events-none" size="1rem" />
        {/snippet}
      </Input>
    </div>

    <!-- ユーザー画像 -->
    <div class="shrink-0 size-10">
      {#if profileImgUrl}
        <img class="size-full rounded-full object-cover" src={profileImgUrl} alt="プロフィール画像" />
      {:else}
        <div class="flex items-center justify-center size-10 border border-border rounded-full">
          <UserRound class="size-3 object-contain text-subtle-foreground" />
        </div>
      {/if}
    </div>
  </div>
</header>

      

依存コンポーネント

Headerを使うときは、以下のコンポーネントもダウンロードが必要です。

使い方

header/default is coming soon.


Header Snippet

Header Snippetは、任意のコンテンツ・ハンバーガーメニュー・プロフィール画像で構成されるヘッダーのサンプルレイアウトです。

header/snippet is coming soon.

プロパティ

Header Snippetは、以下のプロパティをサポートしています。

名前 デフォルト値 説明
mobileMenus MenuItem[] [] SP用のメニューとして表示する値の配列です。
currentIndex number 現在選択されているメニューを示すハイライト用の数値です。
profileImgUrl string '' プロフィール画像のURLです。
startContent Snippet 左側に配置するコンテンツです。

インストールの手順

以下のコンポーネントのコードを、使いたいプロジェクトにコピー&ペーストします。
パスは実際のプロジェクトの構成にあわせて更新します。

modules/HeaderSnippet.svelte
        <!--
@component
## 概要
- HeaderSnippet は、スニペットで左側のコンテンツを自由にカスタマイズできるレスポンシブヘッダーです。
PCではスニペットの内容を左側に、SPでは中央に表示します。

## 機能
- startContentスニペットを受け取り、PCは左端・SPは中央に配置。
- プロフィール画像を右端に表示。
- SPではハンバーガー+ドロワーでメニューを表示。

## Props
- startContent: 左側に配置するコンテンツ。省略可能で、省略した場合は表示されない。
- mobileMenus: SP時(Drawer内)のメニュー。メニューコンポーネントに渡す配列。省略可能で、省略した場合は項目が表示されない。
- currentIndex: 現在表示中のページの位置を示すハイライト。省略可能で、省略した場合はハイライトが表示されない。
- profileImgUrl: 右端に表示するプロフィール画像URL。省略可能で、省略した場合はデフォルトの灰色アイコンになる。
- class: ヘッダー全体に付与する追加クラス。省略可能。

## Usage
```svelte
<HeaderSnippet {mobileMenus} {currentIndex} profileImgUrl="/images/sample.png">
  {#snippet startContent()}
    <a href="/">
      <div class="mask-[url('/images/logo.svg')] mask-contain mask-no-repeat w-28 h-5 bg-foreground transition">
        <h1 class="sr-only">Rabee UI</h1>
      </div>
    </a>
  {/snippet}
</HeaderSnippet>
```
-->

<script module lang="ts">
  import type { MenuItem } from '$lib/components/ui/atoms/Menu.svelte';
  import type { Snippet } from 'svelte';
  import type { ClassValue } from 'svelte/elements';

  /** レスポンシブ切り替えの境界値(この値を下回るとモバイル表示、以上でデスクトップ表示) */
  export const RESPONSIVE_BREAKPOINT_PX = 768;

  export interface HeaderSnippetProps {
    /** 左側に配置するコンテンツ */
    startContent?: Snippet;
    /** メニューとして表示する値の配列(SP用)。メニューコンポーネント用 */
    mobileMenus?: MenuItem[];
    /** 現在選択されているメニューを示すハイライト用の数値 */
    currentIndex?: number;
    /** プロフィール画像のURL */
    profileImgUrl?: string;
    /** 追加クラス */
    class?: ClassValue;
  }
</script>

<script lang="ts">
  import Button from '$lib/components/ui/atoms/Button.svelte';
  import Menu from '$lib/components/ui/atoms/Menu.svelte';
  import Drawer from '$lib/components/ui/modules/Drawer.svelte';
  import Hamburger from '@lucide/svelte/icons/menu';
  import UserRound from '@lucide/svelte/icons/user-round';
  import X from '@lucide/svelte/icons/x';

  let { startContent, mobileMenus = [], currentIndex, profileImgUrl = '', class: className }: HeaderSnippetProps = $props();
  let isOpen = $state(false);
  let viewportWidth = $state<number>(0);

  $effect(() => {
    // SPからPCの幅に切り替わった場合、ドロワーを閉じる。
    if (viewportWidth >= RESPONSIVE_BREAKPOINT_PX) {
      isOpen = false;
    }
  });

  /**
   * ドロワーの開閉状態をトグルする。
   * @param event クリックイベント(バブリングを止める)
   */
  function openDrawer(event: MouseEvent): void {
    event.stopPropagation();
    isOpen = !isOpen;
  }
</script>

<header class={[className, 'relative flex items-center justify-between w-full h-14 px-6 z-50 after:absolute after:bottom-0 after:inset-x-0 after:h-px after:bg-border after:content-[\'\'] after:-z-10 max-md:py-3 max-md:px-4 max-md:h-16']} bind:clientWidth={viewportWidth}>
  <!-- ロゴ -->
  {#if startContent}
    {@render startContent()}
  {/if}

  {#if mobileMenus.length}
    <!-- ハンバーガーアイコン(SP) -->
    <div class="mr-4 md:hidden">
      <Button class="border border-border" type="button" variant="secondary" size="small" tone="solid" isSquare onclick={openDrawer} aria-label="メニューを開く">
        <Hamburger size="1.125rem" />
      </Button>
    </div>

    <!-- ハンバーガーアイコンのクリック時に開くドロワー(SP) -->
    <Drawer class="md:hidden" direction="left" bind:isOpen>
      {#snippet children()}
        <div class="relative flex flex-col justify-between h-full px-4 pt-14">
          <Button class="absolute top-2 right-2" variant="secondary" size="small" tone="ghost" isSquare onclick={() => (isOpen = false)}><X size="1rem" /></Button>
          <!-- メニュー(SP用) -->
          <div class="h-full overflow-y-auto">
            {#each mobileMenus as menu, index}
              <Menu class="w-auto" item={menu} current={currentIndex === index ? menu.id : ''} />
            {/each}
          </div>
        </div>
      {/snippet}
    </Drawer>
  {/if}

  <!-- ユーザー画像 -->
  <div class="shrink-0 size-10">
    {#if profileImgUrl}
      <img class="size-full rounded-full object-cover" src={profileImgUrl} alt="" />
    {:else}
      <div class="flex items-center justify-center size-10 border border-border rounded-full">
        <UserRound class="size-3 object-contain text-subtle-foreground" />
      </div>
    {/if}
  </div>
</header>

      

依存コンポーネント

Header Snippetを使うときは、以下のコンポーネントもダウンロードが必要です。

使い方

header/snippet is coming soon.