Agent Skills by ALSEL
汎用ソフトウェア開発⭐ リポ 39,967品質スコア 95/100

frontend-ui-engineering

プロダクション品質のUIを構築します。ユーザーが目にするインターフェースの構築や修正を行う際に使用してください。コンポーネントの作成、レイアウトの実装、ステート管理など、AIが生成したものではなく、プロダクション品質の外観と操作感が必要な場合に活用できます。

description の原文を見る

Builds production-quality UIs. Use when building or modifying user-facing interfaces. Use when creating components, implementing layouts, managing state, or when the output needs to look and feel production-quality rather than AI-generated.

SKILL.md 本文

フロントエンド UI エンジニアリング

概要

アクセシブルで高性能かつ視覚的に洗練された、本番品質のユーザーインターフェースを構築します。目標は、一流企業のデザイン志向のエンジニアが構築したように見える UI であり、AI が生成したものではないように見える UI です。これは、実際のデザインシステムへの準拠、適切なアクセシビリティ、思慮深いインタラクションパターン、そして一般的な「AI美学」がないことを意味します。

使用する場合

  • 新しい UI コンポーネントまたはページを構築するとき
  • 既存のユーザー向けインターフェースを変更するとき
  • レスポンシブレイアウトを実装するとき
  • インタラクティビティまたは状態管理を追加するとき
  • ビジュアルまたは UX の問題を修正するとき

コンポーネントアーキテクチャ

ファイル構造

コンポーネントに関連するすべてをまとめて配置します:

src/components/
  TaskList/
    TaskList.tsx          # コンポーネント実装
    TaskList.test.tsx     # テスト
    TaskList.stories.tsx  # Storybook ストーリー(使用する場合)
    use-task-list.ts      # カスタムフック(複雑な状態の場合)
    types.ts              # コンポーネント固有の型(必要な場合)

コンポーネントパターン

構成を設定より優先します:

// 良い: コンポーザブル
<Card>
  <CardHeader>
    <CardTitle>Tasks</CardTitle>
  </CardHeader>
  <CardBody>
    <TaskList tasks={tasks} />
  </CardBody>
</Card>

// 回避: 過度に設定している
<Card
  title="Tasks"
  headerVariant="large"
  bodyPadding="md"
  content={<TaskList tasks={tasks} />}
/>

コンポーネントをフォーカスさせます:

// 良い: 1 つのことを行う
export function TaskItem({ task, onToggle, onDelete }: TaskItemProps) {
  return (
    <li className="flex items-center gap-3 p-3">
      <Checkbox checked={task.done} onChange={() => onToggle(task.id)} />
      <span className={task.done ? 'line-through text-muted' : ''}>{task.title}</span>
      <Button variant="ghost" size="sm" onClick={() => onDelete(task.id)}>
        <TrashIcon />
      </Button>
    </li>
  );
}

データフェッチをプレゼンテーションから分離します:

// コンテナ: データを処理
export function TaskListContainer() {
  const { tasks, isLoading, error } = useTasks();

  if (isLoading) return <TaskListSkeleton />;
  if (error) return <ErrorState message="Failed to load tasks" retry={refetch} />;
  if (tasks.length === 0) return <EmptyState message="No tasks yet" />;

  return <TaskList tasks={tasks} />;
}

// プレゼンテーション: レンダリングを処理
export function TaskList({ tasks }: { tasks: Task[] }) {
  return (
    <ul role="list" className="divide-y">
      {tasks.map(task => <TaskItem key={task.id} task={task} />)}
    </ul>
  );
}

状態管理

動作する最もシンプルなアプローチを選択します:

ローカル状態 (useState)           → コンポーネント固有の UI 状態
リフトされた状態                    → 2~3 つのシブリングコンポーネント間で共有
Context                          → テーマ、認証、ロケール(読み取り頻度が高く、書き込み頻度が低い)
URL 状態 (searchParams)          → フィルター、ページネーション、共有可能な UI 状態
サーバー状態 (React Query, SWR)  → キャッシング付きのリモートデータ
グローバルストア (Zustand, Redux) → アプリ全体で共有される複雑なクライアント状態

プロップドリリングを 3 レベルより深くしないようにします。 プロップを使用しないコンポーネント経由で渡している場合は、Context を導入するか、コンポーネントツリーを再構成します。

デザインシステムへの準拠

AI 美学の回避

AI が生成した UI には認識可能なパターンがあります。すべてを回避します:

AI のデフォルト問題である理由本番品質
紫/インディゴばかりモデルは視覚的に「安全な」パレットをデフォルトにするため、すべてのアプリが同じように見えますプロジェクトの実際のカラーパレットを使用します
過度なグラデーショングラデーションは視覚的なノイズを加え、ほとんどのデザインシステムと競合しますデザインシステムに合わせたフラットまたは微妙なグラデーション
すべてを角丸く(rounded-2xl)最大の角丸は「親しみやすさ」を示していますが、実際のデザイン内の border-radius の階層を無視しますデザインシステムの一貫した border-radius
一般的なヒーローセクションテンプレート駆動のレイアウトで、実際のコンテンツまたはユーザーニーズとの関連がありませんコンテンツファースト レイアウト
Lorem ipsum スタイルのコピープレースホルダーテキストはレイアウト問題(長さ、折り返し、オーバーフロー)を隠しますリアルなプレースホルダーコンテンツ
どこでも過度なパディング等しい寛大なパディングは視覚的階層を破壊し、画面スペースを浪費します一貫したスペーシングスケール
一般的なカードグリッド均一なグリッドはレイアウトショートカットであり、情報の優先順位とスキャニングパターンを無視します目的駆動のレイアウト
シャドウが重いデザインレイヤー化されたシャドウはコンテンツと競合する深さを加え、低機能デバイスでレンダリングを低下させますデザインシステムで指定されている場合のみ、微妙なシャドウまたはシャドウなし

スペーシングとレイアウト

一貫したスペーシングスケールを使用します。値を発明しないでください:

/* スケールを使用します: 0.25rem 増分(またはプロジェクトが使用するもの) */
/* 良い */  padding: 1rem;      /* 16px */
/* 良い */  gap: 0.75rem;       /* 12px */
/* 悪い */   padding: 13px;      /* スケール上にない */
/* 悪い */   margin-top: 2.3rem; /* スケール上にない */

タイポグラフィ

タイプ階層を尊重します:

h1 → ページタイトル(ページごとに 1 つ)
h2 → セクションタイトル
h3 → サブセクションタイトル
body → デフォルトテキスト
small → セカンダリ/ヘルパーテキスト

見出しレベルをスキップしないでください。見出しでないコンテンツに見出しスタイルを使用しないでください。

  • セマンティックカラートークンを使用します: text-primarybg-surfaceborder-default — raw hex 値ではなく
  • 十分なコントラストを確保します(通常のテキストは 4.5:1、大きいテキストは 3:1)
  • 色だけに情報伝達を依存しないでください(アイコン、テキスト、またはパターンも使用してください)

アクセシビリティ (WCAG 2.1 AA)

すべてのコンポーネントはこれらの標準を満たさなければなりません:

キーボードナビゲーション

// すべてのインタラクティブ要素はキーボードでアクセス可能である必要があります
<button onClick={handleClick}>Click me</button>        // ✓ デフォルトでフォーカス可能
<div onClick={handleClick}>Click me</div>               // ✗ フォーカス不可
<div role="button" tabIndex={0} onClick={handleClick}    // ✓ ただし <button> を優先
     onKeyDown={e => {
       if (e.key === 'Enter') handleClick();
       if (e.key === ' ') e.preventDefault();
     }}
     onKeyUp={e => {
       if (e.key === ' ') handleClick();
     }}>
  Click me
</div>

ARIA ラベル

// 表示テキストを欠くインタラクティブ要素にラベルを付けます
<button aria-label="Close dialog"><XIcon /></button>

// フォーム入力にラベルを付けます
<label htmlFor="email">Email</label>
<input id="email" type="email" />

// または、表示ラベルが存在しない場合は aria-label を使用します
<input aria-label="Search tasks" type="search" />

フォーカス管理

// コンテンツが変わったときフォーカスを移動します
function Dialog({ isOpen, onClose }: DialogProps) {
  const closeRef = useRef<HTMLButtonElement>(null);

  useEffect(() => {
    if (isOpen) closeRef.current?.focus();
  }, [isOpen]);

  // ダイアログがオープンのときフォーカスを内部にトラップします
  return (
    <dialog open={isOpen}>
      <button ref={closeRef} onClick={onClose}>Close</button>
      {/* ダイアログコンテンツ */}
    </dialog>
  );
}

意味のある空の状態とエラー状態

// 空白の画面を表示しないでください
function TaskList({ tasks }: { tasks: Task[] }) {
  if (tasks.length === 0) {
    return (
      <div role="status" className="text-center py-12">
        <TasksEmptyIcon className="mx-auto h-12 w-12 text-muted" />
        <h3 className="mt-2 text-sm font-medium">No tasks</h3>
        <p className="mt-1 text-sm text-muted">Get started by creating a new task.</p>
        <Button className="mt-4" onClick={onCreateTask}>Create Task</Button>
      </div>
    );
  }

  return <ul role="list">...</ul>;
}

レスポンシブデザイン

モバイルファーストで設計し、その後展開します:

// Tailwind: モバイルファースト レスポンシブ
<div className="
  grid grid-cols-1      /* モバイル: 単一列 */
  sm:grid-cols-2        /* 小: 2 列 */
  lg:grid-cols-3        /* 大: 3 列 */
  gap-4
">

これらのブレークポイントでテストします: 320px、768px、1024px、1440px。

ローディングとトランジション

// スケルトンローディング(コンテンツにはスピナーではなく)
function TaskListSkeleton() {
  return (
    <div className="space-y-3" aria-busy="true" aria-label="Loading tasks">
      {Array.from({ length: 3 }).map((_, i) => (
        <div key={i} className="h-12 bg-muted animate-pulse rounded" />
      ))}
    </div>
  );
}

// 認識される速度のための楽観的更新
function useToggleTask() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: toggleTask,
    onMutate: async (taskId) => {
      await queryClient.cancelQueries({ queryKey: ['tasks'] });
      const previous = queryClient.getQueryData(['tasks']);

      queryClient.setQueryData(['tasks'], (old: Task[]) =>
        old.map(t => t.id === taskId ? { ...t, done: !t.done } : t)
      );

      return { previous };
    },
    onError: (_err, _taskId, context) => {
      queryClient.setQueryData(['tasks'], context?.previous);
    },
  });
}

参考資料

詳細なアクセシビリティ要件とテストツールについては、references/accessibility-checklist.md を参照してください。

一般的な正当化

正当化実情
「アクセシビリティはあると良い」多くの管轄区域では法的要件であり、エンジニアリング品質基準です。
「後でレスポンシブにします」レスポンシブデザインの後付けは、最初から構築するより 3 倍難しいです。
「デザインはまだ確定していないのでスタイリングはスキップします」デザインシステムのデフォルトを使用します。スタイルなし UI は審査者に壊れた第一印象を与えます。
「これはプロトタイプです」プロトタイプは本番コードになります。基盤を正しく構築します。
「AI 美学は今のところ大丈夫です」それは低品質を示唆します。最初からプロジェクトの実際のデザインシステムを使用します。

レッドフラグ

  • 200 行以上のコンポーネント(分割します)
  • インラインスタイルまたは任意のピクセル値
  • エラー状態、ローディング状態、または空の状態がない
  • キーボードナビゲーションテストがない
  • 状態の唯一のインジケーターとしての色(テキストまたはアイコンなしの赤/緑)
  • 一般的な「AI ルック」(紫のグラデーション、オーバーサイズカード、ストックレイアウト)

検証

UI を構築した後:

  • コンポーネントがコンソールエラーなしでレンダリングされます
  • すべてのインタラクティブ要素はキーボードでアクセス可能です(ページをタブで移動します)
  • スクリーンリーダーがページのコンテンツと構造を伝えることができます
  • レスポンシブ: 320px、768px、1024px、1440px で動作します
  • ローディング、エラー、空の状態がすべて処理されます
  • プロジェクトのデザインシステムに従っています(スペーシング、色、タイポグラフィ)
  • 開発者ツールまたは axe-core のアクセシビリティ警告がありません

ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ

詳細情報

作者
addyosmani
リポジトリ
addyosmani/agent-skills
ライセンス
MIT
最終更新
2026/5/10

Source: https://github.com/addyosmani/agent-skills / ライセンス: MIT

本サイトは GitHub 上で公開されているオープンソースの SKILL.md ファイルをクロール・インデックス化したものです。 各スキルの著作権は原作者に帰属します。掲載に問題がある場合は info@alsel.co.jp または /takedown フォームよりご連絡ください。
原作者: addyosmani · addyosmani/agent-skills · ライセンス: MIT