セットアップ

要件

Tailwind UIのすべてのコンポーネントは、最新のTailwind CSSバージョン(現在、Tailwind CSS v3.4)用に設計されています。最新のTailwindバージョンを使用していることを確認するには、npm経由でアップデートしてください。

npm install tailwindcss@latest

Tailwind UIのすべての例は、デフォルトのTailwind CSS設定に依存していますが、@tailwindcss/forms@tailwindcss/typography@tailwindcss/aspect-ratioなどの追加のファーストパーティープラグインに依存するものもあります。

例でプラグインまたは設定の変更が必要な場合は、例のトップにあるコメントに記載されます。

Tailwind CSSを初めて使用する場合は、Tailwind UIを最大限に活用するためにTailwind CSSのドキュメントも参照してください。

オプション:Interフォントファミリーを追加する

UIデザインに最適な美しいオープンソースで無料のフォントであるInterを、すべてのTailwind UIの例で使用しています。カスタムフォントを使用すると、すべてのブラウザとオペレーティングシステムでコンポーネントを同じように表示できます。

もちろん、独自のプロジェクトでは任意のフォントを使用できますが、Interを使用したい場合は、最初にCDN経由で追加するのが最も簡単な方法です。

<link rel="stylesheet" href="https://rsms.me/inter/inter.css">

次に、Tailwindの設定で「Inter var」を「sans」フォントファミリーに追加します。

// tailwind.config.js
const defaultTheme = require('tailwindcss/defaultTheme')

module.exports = {
  theme: {
    extend: {
      fontFamily: {
        sans: ['Inter var', ...defaultTheme.fontFamily.sans],
      },
    },
  },
  // ...
}

HTMLと独自のJSを使用する

Tailwind UIのすべてのコンポーネントは、React、Vue、およびプレーンHTMLの3つの形式で提供されています。

ReactとVueの例は、すぐに使用でき、Headless UI(Tailwind CSSと完全に統合するように設計された、スタイルのないコンポーネントのライブラリ)によって強化されています。

プレーンHTMLの例には**JavaScriptは含まれていません**。独自のJavaScriptを記述したい人、またはReactやVue以外のフレームワークと統合したい人のために設計されています。

ほとんどのコンポーネントはJavaScriptをまったく必要とせず、すぐに使用できますが、ドロップダウンやダイアログなど、インタラクティブなものは、期待どおりに動作させるためにいくつかのJSを記述する必要があります。

このような場合、HTMLに簡単なコメントを追加して、さまざまな状態(オンまたはオフのトグルスイッチなど)に必要なクラス、または画面上または画面外への要素のトランジション(ダイアログの開閉など)に推奨されるクラスを説明しています。

アクセシビリティに関する考慮事項

Tailwind UIのすべてのマークアップが可能な限りアクセシブルであるように最善を尽くしていますが、インタラクティブなコンポーネントを構築する際には、**多くのアクセシビリティのベストプラクティスはJavaScriptでのみ実装できます。**

例えば

  • **コンポーネントがキーボードで適切にアクセス可能であることを確認する**(ドロップダウンは上下の矢印キーで移動する必要がある、ダイアログはEscapeキーを押すと閉じなければならない、タブは左右の矢印キーで選択する必要があるなど)
  • **フォーカスを正しく処理する**(ダイアログの後ろの要素にタブで移動できない、ドロップダウンの最初のアイテムはドロップダウンが開くと自動的にフォーカスされるなど)
  • **ARIA属性とコンポーネントの状態を同期させる**(ドロップダウンが開いているときにaria-expanded="true"を追加する、トグルがオンのときにaria-checkedをtrueに設定する、オートコンプリートのオプションを移動するときにaria-activedescendantを更新するなど)
  • …など、多くの懸念事項があります。

ReactまたはVueでTailwind UIを使用している場合、これらすべての複雑さはHeadless UIによって自動的に処理されますが、独自のJSを提供する場合は、**インタラクティブな動作を追加する際にアクセシビリティのベストプラクティスに従う必要があります。**

アクセシブルなUIコンポーネントの構築の詳細については、W3Cが公開したWAI-ARIAオーサリングプラクティスを学習することをお勧めします。

動的なクラス

要素に状態に基づいて異なるクラスを適用する必要がある場合(オンまたはオフのトグルなど)、その状態のクラスを要素の直上のコメントにリストします。

<!-- On: "bg-indigo-600", Off: "bg-gray-200" -->
<span aria-checked="false" class="bg-gray-200 relative inline-block flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:shadow-outline" role="checkbox" tabindex="0">
  <!-- On: "translate-x-5", Off: "translate-x-0" -->
  <span aria-hidden="true" class="translate-x-0 inline-block h-5 w-5 rounded-full bg-white shadow transform transition ease-in-out duration-200"></span>
</span>

**提供するHTMLは、常に定義された状態の1つに事前に設定されており**、状態を切り替える際に変更する必要があるクラスは常にクラスリストの先頭に配置されているため、簡単に検索できます。

例として、このHTMLをAlpine.jsに適応させるには、x-dataで宣言した状態に基づいて、:classディレクティブを使用して適切なクラスを条件付きで適用できます。

<span
  x-data="{ isOn: false }"
  @click="isOn = !isOn"
  :aria-checked="isOn"
  :class="{'bg-indigo-600': isOn, 'bg-gray-200': !isOn }"
  class="bg-gray-200 relative inline-block flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:shadow-outline"
  role="checkbox"
  tabindex="0"
>
  <span
    aria-hidden="true"
    :class="{'translate-x-5': isOn, 'translate-x-0': !isOn }"
    class="translate-x-0 inline-block h-5 w-5 rounded-full bg-white shadow transform transition ease-in-out duration-200"
  ></span>
</span>

ここでは基本的なクリックハンドラを含めて一般的なアイデアを示していますが、**このようなコンポーネントを構築する際にはWAI-ARIAオーサリングプラクティスを参照して**、必要なキーボード操作をすべて実装し、必要なARIA属性を適切に管理してください。

トランジション

動的に表示または非表示にする必要がある要素(ドロップダウンのパネルなど)には、動的要素の直上のコメントに推奨されるトランジションスタイルを含めます。

<div class="relative ...">
  <button type="button" class="...">
    Options
  </button>

  <!--
    Show/hide this element based on the dropdown state

    Entering: "transition ease-out duration-100 transform"
      From: "opacity-0 scale-95"
      To: "opacity-100 scale-100"
    Closing: "transition ease-in duration-75 transform"
      From: "opacity-100 scale-100"
      To: "opacity-0 scale-95"
  -->
  <div class="origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg">
    <div class="rounded-md bg-white shadow-xs">
      <!-- Snipped  -->
    </div>
  </div>
</div>

例として、このHTMLをAlpine.jsに適応させるには、x-transitionディレクティブを使用して、トランジションライフサイクルの各時点で適切なクラスを適用します。

<div x-data="{ isOpen: false }" class="relative ...">
  <button type="button" @click="isOpen = !isOpen" class="...">
    Options
  </button>

  <div
    x-show="isOpen"
    x-transition:enter="transition ease-out duration-100 transform"
    x-transition:enter-start="opacity-0 scale-95"
    x-transition:enter-end="opacity-100 scale-100"
    x-transition:leave="transition ease-in duration-75 transform"
    x-transition:leave-start="opacity-100 scale-100"
    x-transition:leave-end="opacity-0 scale-95"
    class="origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg"
  >
    <div class="rounded-md bg-white shadow-xs">
      <!-- Snipped  -->
    </div>
  </div>
</div>

ここでは基本的なクリックハンドラを含めて一般的なアイデアを示していますが、**このようなコンポーネントを構築する際にはWAI-ARIAオーサリングプラクティスを参照して**、必要なキーボード操作をすべて実装し、必要なARIA属性を適切に管理してください。

partials/コンポーネントの作成

Tailwind UIに含まれるプレーンHTMLの例は、ループなどの機能を利用できないため、実際のプロジェクトでは動的なデータソースからHTMLが生成されるため、実際には存在しない多くの繰り返しがあります。たとえば、各ユーティリティが複製された5つのリストアイテムを持つリストコンポーネントを提供する場合がありますが、プロジェクトでは配列をループ処理してリストアイテムを生成します。

独自のプロジェクトに例を適応させる際には、必要に応じて再利用可能なテンプレートpartialsまたはJSコンポーネントを作成して、重複を管理することをお勧めします。

Tailwind CSS Webサイトの"コンポーネントの抽出"ドキュメントで詳細を学ぶことができます。


Reactの使用

依存関係のインストール

React用のTailwind UIは、インタラクティブな動作をすべて実行するためにHeadless UIに依存し、アイコンにはHeroiconsを使用するため、プロジェクトにこれらの2つのライブラリを追加する必要があります。

npm install @headlessui/react @heroicons/react

これらのライブラリとTailwind UI自体は、React >= 16が必要です。.

コンポーネントの作成

Reactの例はすべて、シンプルな単一コンポーネントとして提供されており、どのようにコンポーネントを分割するか、公開するプロップAPI、データの取得元については一切想定していません。

コードの重複を解消し、可読性と理解しやすさを向上させるために、一部のデータは基本的なローカル変数に抽出されていますが、不必要に厳格な意見を押し付けることを避けるため、最小限の変更にとどめています。

Tailwind UIのコードを自身のプロジェクトに適用する際は、プロジェクトに必要な再利用レベルを実現するために、必要に応じて例をより小さなコンポーネントに分割してください。

例えば、この積み重ねられたリストコンポーネントから始めることができます。

const people = [
  {
    name: 'Calvin Hawkins',
    email: 'calvin.hawkins@example.com',
    image:
      'https://images.unsplash.com/photo-1491528323818-fdd1faba62cc?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80',
  },
  {
    name: 'Kristen Ramos',
    email: 'kristen.ramos@example.com',
    image:
      'https://images.unsplash.com/photo-1550525811-e5869dd03032?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80',
  },
  {
    name: 'Ted Fox',
    email: 'ted.fox@example.com',
    image:
      'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80',
  },
]

export default function Example() {
  return (
    <ul className="divide-y divide-gray-200">
      {people.map((person) => (
        <li key={person.email} className="py-4 flex">
          <img className="h-10 w-10 rounded-full" src={person.image} alt="" />
          <div className="ml-3">
            <p className="text-sm font-medium text-gray-900">{person.name}</p>
            <p className="text-sm text-gray-500">{person.email}</p>
          </div>
        </li>
      ))}
    </ul>
  )
}

自身のプロジェクトに合わせてコンテンツを調整し、別々のコンポーネントに分割してデータソースを接続した後、このような見た目になるかもしれません。

function HockeyTeamItem({ team }) {
  return (
    <li className="py-4 flex">
      <img className="h-10 w-10 rounded-full" src={team.logo} alt="" />
      <div className="ml-3">
        <p className="text-sm font-medium text-gray-900">{team.name}</p>
        <p className="text-sm text-gray-500">{team.city}</p>
      </div>
    </li>
  )
}

export default function HockeyTeamList({ teams }) {
  return (
    <ul className="divide-y divide-gray-200">
      {teams.map((team) => <HockeyTeamItem key={team.id} team={team} />)}
    </ul>
  )
}

Tailwind UIは、厳格なUIキットというよりも、設計図、パターン、アイデアの集合体です。最終的に作成されるコードはあなた自身のものであり、自由に構成することができます。


Vueの使用

依存関係のインストール

Vue用のTailwind UIは、すべてのインタラクティブな動作にHeadless UI、アイコンにHeroiconsに依存しているため、これらの2つのライブラリをプロジェクトに追加する必要があります。

npm install @headlessui/vue @heroicons/vue

これらのライブラリとTailwind UI自体は、Vue 3以降が必要です。現在、Vue 2はサポートしていません。

コンポーネントの作成

Vueの例はすべて、シンプルな単一コンポーネントとして提供されており、どのようにコンポーネントを分割するか、公開するプロップAPI、データの取得元については一切想定していません。

コードの重複を解消し、可読性と理解しやすさを向上させるために、一部のデータは基本的なローカル変数に抽出されていますが、不必要に厳格な意見を押し付けることを避けるため、最小限の変更にとどめています。

Tailwind UIのコードを自身のプロジェクトに適用する際は、プロジェクトに必要な再利用レベルを実現するために、必要に応じて例をより小さなコンポーネントに分割してください。

例えば、この積み重ねられたリストコンポーネントから始めることができます。

<template>
  <ul class="divide-y divide-gray-200">
    <li v-for="person in people" :key="person.email" class="py-4 flex">
      <img class="h-10 w-10 rounded-full" :src="person.image" alt="" />
      <div class="ml-3">
        <p class="text-sm font-medium text-gray-900">{{ person.name }}</p>
        <p class="text-sm text-gray-500">{{ person.email }}</p>
      </div>
    </li>
  </ul>
</template>

<script>
const people = [
  {
    name: 'Calvin Hawkins',
    email: 'calvin.hawkins@example.com',
    image:
      'https://images.unsplash.com/photo-1491528323818-fdd1faba62cc?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80',
  },
  {
    name: 'Kristen Ramos',
    email: 'kristen.ramos@example.com',
    image:
      'https://images.unsplash.com/photo-1550525811-e5869dd03032?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80',
  },
  {
    name: 'Ted Fox',
    email: 'ted.fox@example.com',
    image:
      'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80',
  },
]

export default {
  setup() {
    return {
      people,
    }
  },
}
</script>

自身のプロジェクトに合わせてコンテンツを調整し、別々のコンポーネントに分割してデータソースを接続した後、このような見た目になるかもしれません。

<!-- HockeyTeamList.vue -->
<template>
  <ul class="divide-y divide-gray-200">
    <HockeyTeamItem v-for="team in teams" :key="team.id" :team="team"/>
  </ul>
</template>

<script>
export default {
  props: {
    teams: Array
  },
}
</script>

<!-- HockeyTeamListItem.vue -->
<template>
  <li class="py-4 flex">
    <img class="h-10 w-10 rounded-full" :src="team.logo" alt="" />
    <div class="ml-3">
      <p class="text-sm font-medium text-gray-900">{{ team.name }}</p>
      <p class="text-sm text-gray-500">{{ team.city }}</p>
    </div>
  </li>
</template>

<script>
export default {
  props: {
    team: Object
  },
}
</script>

Tailwind UIは、厳格なUIキットというよりも、設計図、パターン、アイデアの集合体です。最終的に作成されるコードはあなた自身のものであり、自由に構成することができます。


リソースとアセット

アイコン

Tailwind UIで使用しているアイコンはすべて、Heroiconsからのものです。これは、Tailwind UIの開発を開始した際に、私たち自身で設計・開発した、MITライセンスの無料アイコンセットです。

画像

Tailwind UIの画像は、ほとんどすべてUnsplashからのものです。プロジェクトで自由に使用できる写真が必要な場合、優れたリソースとなります。

イラスト

Tailwind UIの一部の例では、Pixsellzによる無料のLucid Illustrationsパックからのイラストを使用しています。ウェブサイトで、イラストのフルセットを入手し、他のデザインリソースを確認できます。

Figmaアセット

より優れたTailwind CSSの例の作成に注力するため、Figmaアセットの提供を中止しました。

以前はTailwind UIのFigmaアセットを提供していましたが、メンテナンスには膨大な作業が必要であり、利用者も非常に少なかったため、実際のコードにより多くの時間を費やすことができるよう、提供中止という非常に難しい決定をしました。コードこそが、私たちが最大の価値を提供できると考えている場所です。

Tailwind UIのお客様は、最後にリリースされたFigmaファイルのダウンロードが可能です。ただし、Figmaファイルは更新されませんのでご注意ください。2021年7月14日以降にリリースされた例は含まれていません。