vaadin-frontend-design について
JavaとCSSで個性のあるVaadinインターフェースを構築するためのスキルです。テーマ選択やビジュアル調整、コンポーネントの仕上げを案内し、Vaadin MCPのドキュメントツールでAPIの詳細を確認します。
主な機能
- 01一貫したビジュアル方針を計画
- 02AuraとLumoのテーマをカスタマイズ
- 03文字、色、余白を調整
- 04バリアントとCSSでコンポーネントをスタイリング
- 05Vaadin MCPツールでドキュメントを検索
活用シーン
- 01ブランドに沿ったVaadinダッシュボードを設計
- 02文字と配色の体系を調整
- 03既定の外観を超えてコンポーネントをスタイリング
- 04実装中にVaadin APIの詳細を確認
MCP 対応
`search_vaadin_docs`、`get_component_styling`、`get_component_java_api`などのVaadin MCPツールを使い、ドキュメントやコンポーネントの詳細を調べるよう案内します。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ vaadin/ agent-skills --skill vaadin-frontend-designインストール後、Claude Code で/vaadin-frontend-designを入力して読み込まれたか確認します。
同梱ファイルreferences/design-patterns.md
詳細
個性的な Vaadin インターフェースの作成
特定の API の詳細が不確かな場合は、Vaadin MCP ツール(search_vaadin_docs、get_component_styling、get_component_java_api)を使って最新のドキュメントを確認してください。常に vaadin_version を "25" に、ui_language を "java" に設定してください。
このスキルでは、デフォルトのテーマスタイルにとどまらない、個性的で洗練された Vaadin インターフェースの作成方法を説明します。目指すのは、美的な細部にも真摯にこだわった、本番環境に対応するコードです。ありきたりなデフォルト設定ではありません。
デザインの考え方
コードを書く前に、コンテキストを把握し、明確な美的方向性を定めてください。
- 目的:このインターフェースはどのような問題を解決しますか?誰が使いますか?管理者用ダッシュボードと顧客向けポータルでは、デザインの要件が異なります。
- トーン:方向性を選びます。すっきりとしたプロフェッショナルなデザイン、温かみがあり親しみやすいデザイン、大胆でデータ密度の高いデザイン、明るく軽やかなデザイン、暗く集中しやすいデザイン、エディトリアル、遊び心のあるデザイン、洗練されたデザインなどです。方向性は、ユーザーとコンテンツに合ったものにしてください。
- 制約:Vaadin コンポーネントライブラリ、Vaadin テーマシステム(Aura または Lumo)、サーバーサイドレンダリングモデル、アクセシビリティ要件。
- 差別化:このインターフェースをデフォルトではなく、丁寧に作り込まれたものと感じさせる要素は何ですか?ユーザーが気づく細部は何ですか?
重要:明確な方向性を選び、一貫して実行してください。色、余白、タイポグラフィの選択すべてで、同じ美的方向性を強調してください。一貫性のあるシンプルなデザインは、まとまりのない凝ったデザインに必ず勝ります。
そのうえで、次の条件を満たす動作するコード(Java + CSS)を実装してください。
- 本番環境に対応し、機能すること
- 明確な美的観点に基づき、視覚的に一貫していること
- Vaadin のコンポーネントライブラリとテーマシステムを使用していること
- 余白、色、タイポグラフィ、視覚的階層が洗練されていること
Vaadin テーマシステム
視覚的なカスタマイズは、選択したテーマ(Aura または Lumo)から始めます。どちらのテーマも、次の要素を備えています。
- CSS カスタムプロパティ — 色、タイポグラフィ、余白、サイズ、境界線、影の基盤です。これらを上書きすると、アプリケーション全体の外観を変更できます。
- コンポーネントのテーマバリアント — あらかじめ用意された視覚的なバリエーション(例:プライマリ、ターシャリ、コンパクト)です。カスタム CSS を記述する前に使用してください。
- カスタム CSS — テーマで対応できない要素に使用します。ビューのスコープに限定した CSS ファイルには
@StyleSheetを使ってください。
Lumo には、さらに次の機能があります。
- ユーティリティクラス — レイアウト、余白、色に使える Tailwind に似たクラス(
LumoUtility.*)です。Java からすばやく適用できます。Aura では利用できません。
常に上位の設定から順に取り組んでください。コンポーネント固有の CSS を書く前にテーマのプロパティを変更し、カスタムスタイルを書く前にテーマバリアントを使ってください。
Aura のデザイントークンの全一覧については、aura-theme スキルとその references/property-values.md を参照してください。Lumo トークンと、両方のテーマで共有される --vaadin-* 基本プロパティについては、theme を "lumo" または "base" に設定して get_theme_css_properties を呼び出してください。テーマの選択と読み込みについては、search_vaadin_docs を使ってください。
タイポグラフィ
タイポグラフィは、インターフェース全体のトーンを決定します。
フォントファミリーのカスタマイズ(両方のテーマで使用可能):
/* In styles.css */
@font-face {
font-family: 'Your Font';
src: url('./fonts/your-font.woff2') format('woff2');
font-display: swap;
}
html {
/* Aura */
--aura-font-family: 'Your Font', sans-serif;
/* Lumo */
--lumo-font-family: 'Your Font', sans-serif;
}
文字サイズのスケールの調整:
Aura — 1 つの値を調整すると、スケール全体が計算されます。
html {
--aura-base-font-size: 15; /* unitless number, represents px */
}
Lumo — トークンを個別に上書きします。
html {
--lumo-font-size-xxxl: 2.5rem;
--lumo-font-size-xxl: 1.75rem;
--lumo-font-size-xl: 1.375rem;
--lumo-font-size-l: 1.125rem;
--lumo-font-size-m: 1rem;
--lumo-font-size-s: 0.875rem;
--lumo-font-size-xs: 0.8125rem;
--lumo-font-size-xxs: 0.75rem;
}
Java からタイポグラフィの階層を作成する(Lumo ユーティリティクラス):
// Lumo theme only — requires Lumo.UTILITY_STYLESHEET
H2 title = new H2("Dashboard");
title.addClassNames(
LumoUtility.FontSize.XXLARGE,
LumoUtility.FontWeight.BOLD,
LumoUtility.TextColor.HEADER
);
Span subtitle = new Span("Weekly performance overview");
subtitle.addClassNames(
LumoUtility.FontSize.MEDIUM,
LumoUtility.TextColor.SECONDARY
);
Aura では、LumoUtility の代わりに CSS クラスまたはインラインスタイルを使ってください。
重要な原則:明確な階層を作りましょう。主役となる見出しスタイルを 1 つ、本文スタイルを 1 つ、サブスタイルまたはキャプションスタイルを 1 つ用意します。フォントサイズ、太さ、色を組み合わせて、階層を区別してください。1 つのビューで異なるテキストスタイルを 3~4 種類以上使わないようにしてください。
色とテーマ設定
色は、Vaadin アプリに個性的なアイデンティティを与える最も手早い方法です。
Aura — アクセントとパレットのカスタマイズ:
html {
--aura-accent-color-light: hsl(220, 80%, 50%);
--aura-accent-color-dark: hsl(220, 85%, 65%);
--aura-background-color-light: hsl(220, 20%, 98%);
--aura-background-color-dark: hsl(220, 20%, 12%);
--aura-blue: hsl(220, 80%, 50%);
--aura-green: hsl(150, 60%, 40%);
--aura-red: hsl(0, 75%, 55%);
}
Lumo — カラーパレットの上書き:
html {
/* Primary color — used for buttons, links, focus rings */
--lumo-primary-color: hsl(220, 80%, 50%);
--lumo-primary-color-50pct: hsla(220, 80%, 50%, 0.5);
--lumo-primary-color-10pct: hsla(220, 80%, 50%, 0.1);
--lumo-primary-text-color: hsl(220, 80%, 45%);
--lumo-primary-contrast-color: #fff;
/* Surface colors — backgrounds, cards, dialogs */
--lumo-base-color: hsl(220, 20%, 98%);
/* Error, success, warning */
--lumo-error-color: hsl(0, 75%, 55%);
--lumo-success-color: hsl(150, 60%, 40%);
--lumo-warning-color: hsl(40, 95%, 50%);
}
ダークモード:
どちらのテーマも @ColorScheme アノテーションに対応しています。カスタムのダークモードカラーでは、Aura は -light/-dark サフィックス付きのプロパティを使用します(aura-theme スキルを参照してください)。Lumo は CSS の light-dark() 関数を使用します。たとえば、--lumo-primary-color: light-dark(blue, lightskyblue) のように指定すると、すべてのカラースキームモードで機能します。[theme~="dark"] セレクターは、スキームが ColorScheme.Value.DARK に設定されている場合にのみ一致します。
Java からのアクセントカラーとセマンティックカラー(Lumo ユーティリティクラス):
// Lumo theme only
badge.addClassNames(
LumoUtility.Background.PRIMARY,
LumoUtility.TextColor.PRIMARY_CONTRAST
);
warningCard.addClassNames(
LumoUtility.Background.WARNING_10PCT,
LumoUtility.TextColor.WARNING
);
重要な原則:統一感のあるパレットを採用してください。強いプライマリカラーまたはアクセントカラーを1色選び、二次的な用途にはテーマのバリアントシステム(Lumo の不透明度バリアント、Aura の計算済みバリアント)を使用します。均等に配置された虹色の配色よりも、プライマリカラーを際立たせ、アクセントカラーを控えめに使うほうが効果的です。
余白と密度
一貫した余白は、視覚的なリズムとプロフェッショナルな印象を生み出します。
Aura — ベースサイズの調整:
html {
--aura-base-size: 18; /* unitless, range 12–24 */
--aura-base-radius: 8; /* unitless, range 0–10 */
}
Lumo — 個別の余白トークンの上書き:
html {
--lumo-space-xs: 0.25rem;
--lumo-space-s: 0.5rem;
--lumo-space-m: 1rem;
--lumo-space-l: 1.5rem;
--lumo-space-xl: 2.5rem;
}
Java からの余白の適用(Lumo ユーティリティクラス):
// Lumo theme only
card.addClassNames(
LumoUtility.Padding.LARGE,
LumoUtility.Gap.MEDIUM
);
section.addClassNames(
LumoUtility.Padding.Horizontal.LARGE,
LumoUtility.Padding.Vertical.XLARGE
);
コンパクト/高密度バリアント:
// Cross-theme variants — work in both Aura and Lumo
grid.addThemeVariants(GridVariant.NO_BORDER);
textField.addThemeVariants(TextFieldVariant.SMALL);
button.addThemeVariants(ButtonVariant.SMALL);
// Lumo-only: compact grid
grid.addThemeVariants(GridVariant.LUMO_COMPACT);
重要な原則:密度を決めたら、それを一貫して維持してください。データ密度の高いダッシュボードは、全体を通してコンパクトにします。ゆとりのあるマーケティングスタイルのビューは、全体を通して広々とさせます。密度を混在させると、意図的でない印象になります。
影、境界線、エレベーション
エレベーションによって奥行きと視覚的な階層を作ります。
Aura — サーフェスレベルシステム:
.elevated-card {
background: var(--aura-surface-color);
--aura-surface-level: 2;
}
.sunken-area {
background: var(--aura-surface-color);
--aura-surface-level: -1;
}
Lumo — 明示的な影トークン:
html {
--lumo-box-shadow-xs: 0 1px 2px 0 rgba(0,0,0,0.05);
--lumo-box-shadow-s: 0 2px 4px -1px rgba(0,0,0,0.1);
--lumo-box-shadow-m: 0 4px 8px -2px rgba(0,0,0,0.1);
--lumo-box-shadow-l: 0 8px 16px -4px rgba(0,0,0,0.15);
--lumo-box-shadow-xl: 0 16px 32px -8px rgba(0,0,0,0.2);
}
// Lumo theme only
card.addClassNames(
LumoUtility.BoxShadow.SMALL,
LumoUtility.BorderRadius.MEDIUM
);
角丸のカスタマイズ:
/* Lumo */
html {
--lumo-border-radius-s: 4px;
--lumo-border-radius-m: 8px;
--lumo-border-radius-l: 16px;
}
/* Aura — adjust the base radius instead */
html {
--aura-base-radius: 8; /* computes all radius values */
}
区切りのための控えめな境界線(Lumo ユーティリティクラス):
// Lumo theme only
section.addClassNames(
LumoUtility.Border.BOTTOM,
LumoUtility.BorderColor.CONTRAST_10
);
重要な原則:階層を伝えるために、エレベーションを一貫して使用してください。カードはサーフェスより浮かび上がり、ダイアログはカードより浮かび上がります。平坦な要素に強い影を付けたり、浮いている要素に平坦な影を付けたりしないでください。
動きとアニメーション
Vaadin のサーバーサイドモデルでは、アニメーションは CSS で制御する必要があります。控えめで、目的のある動きにしてください。
CSS によるビュー遷移:
/* Fade-in for view content */
.fade-in {
animation: fadeIn 0.3s ease-out;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(8px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Staggered reveal for list items */
.stagger-item {
animation: fadeIn 0.3s ease-out backwards;
}
.stagger-item:nth-child(1) { animation-delay: 0.05s; }
.stagger-item:nth-child(2) { animation-delay: 0.1s; }
.stagger-item:nth-child(3) { animation-delay: 0.15s; }
.stagger-item:nth-child(4) { animation-delay: 0.2s; }
.stagger-item:nth-child(5) { animation-delay: 0.25s; }
content.addClassName("fade-in");
// Staggered card reveal
for (Component card : cards) {
card.addClassName("stagger-item");
}
ホバーとインタラクションの効果:
.interactive-card {
transition: box-shadow 0.2s ease, transform 0.2s ease;
}
.interactive-card:hover {
box-shadow: 0 4px 8px -2px rgba(0,0,0,0.1); /* or use theme token */
transform: translateY(-2px);
}
重要な原則:ページ読み込み時に段階的に表示する演出など、丁寧に作り込んだアニメーションを1つか2つ使うほうが、マイクロインタラクションをあちこちに散りばめるより大きな効果を生みます。複雑なキーフレームアニメーションよりも、ホバー/フォーカス時の CSS トランジションを優先してください。再生時間は400ms未満にしてください。
洗練されたコンポーネントの構築
スタイル付きカード(Lumo ユーティリティクラス)
// Lumo theme only — uses LumoUtility classes
public static Div createCard(String title, String value, String description) {
Div card = new Div();
card.addClassNames(
LumoUtility.Background.BASE,
LumoUtility.BorderRadius.MEDIUM,
LumoUtility.BoxShadow.SMALL,
LumoUtility.Padding.LARGE,
LumoUtility.Display.FLEX,
LumoUtility.FlexDirection.COLUMN,
LumoUtility.Gap.SMALL
);
Span titleSpan = new Span(title);
titleSpan.addClassNames(
LumoUtility.FontSize.SMALL,
LumoUtility.TextColor.SECONDARY,
LumoUtility.FontWeight.MEDIUM
);
Span valueSpan = new Span(value);
valueSpan.addClassNames(
LumoUtility.FontSize.XXLARGE,
LumoUtility.FontWeight.BOLD,
LumoUtility.TextColor.HEADER
);
Span descSpan = new Span(description);
descSpan.addClassNames(
LumoUtility.FontSize.SMALL,
LumoUtility.TextColor.TERTIARY
);
card.add(titleSpan, valueSpan, descSpan);
return card;
}
Aura では、LumoUtility の代わりに、Aura のサーフェスシステムを使用する CSS クラスを使います。
.metric-card {
background: var(--aura-surface-color);
--aura-surface-level: 2;
border-radius: var(--vaadin-border-radius-m);
padding: var(--vaadin-padding);
display: flex;
flex-direction: column;
gap: 0.5rem;
}
ステータスバッジ
Badge は Vaadin 25.1 のプレビュー機能です。badgeComponent 機能フラグを有効にして使用してください。利用可能なバリアント:SUCCESS、WARNING、ERROR、FILLED、ICON_ONLY、NUMBER_ONLY。
// Badge component (Vaadin 25.1+ preview — requires badgeComponent feature flag)
Badge pending = new Badge("Pending");
Badge confirmed = new Badge("Confirmed");
confirmed.addThemeVariants(BadgeVariant.SUCCESS);
Badge warning = new Badge("Warning");
warning.addThemeVariants(BadgeVariant.WARNING);
Badge denied = new Badge("Denied");
denied.addThemeVariants(BadgeVariant.ERROR);
// With icon
Badge iconBadge = new Badge("Confirmed", VaadinIcon.CHECK.create());
iconBadge.addThemeVariants(BadgeVariant.SUCCESS);
// With number
Badge counter = new Badge("Inbox", 12);
counter.addThemeVariants(BadgeVariant.FILLED);
Vaadin 25.1 より前のバージョンでは、theme="badge" 属性を使用した Span 要素でバッジを作成できますが、この方法は非推奨です。
データ密度の高いダッシュボードレイアウト(Lumo ユーティリティクラス)
// Lumo theme only — uses LumoUtility classes
VerticalLayout dashboard = new VerticalLayout();
dashboard.setPadding(true);
dashboard.setSpacing(false);
dashboard.addClassNames(
LumoUtility.Gap.LARGE,
LumoUtility.Background.CONTRAST_5
);
// Metric cards grid — uses CSS Grid for responsive layout
Div metrics = new Div(
createCard("Revenue", "$48,200", "+12% from last month"),
createCard("Users", "1,420", "+5% from last month"),
createCard("Orders", "384", "+8% from last month")
);
metrics.addClassName("metrics-grid");
// Companion CSS:
// .metrics-grid {
// display: grid;
// grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
// gap: var(--lumo-space-m);
// width: 100%;
// }
dashboard.add(createSectionHeader("Overview"), metrics);
CSS による Vaadin コンポーネントのスタイリング
テーマプロパティやテーマバリアントだけでは不十分な場合は、CSS を使用します。
Shadow DOM と ::part() セレクター — Vaadin コンポーネントは Shadow DOM を使用します。::part() で内部パーツをスタイリングします。
/* Style Grid header cells */
vaadin-grid::part(header-cell) {
background-color: var(--lumo-contrast-5pct); /* Lumo */
/* or for Aura: --aura-surface-level: 0; */
font-weight: 600;
}
/* Style Dialog overlay */
vaadin-dialog-overlay::part(overlay) {
border-radius: 16px;
}
/* Style TextField input */
vaadin-text-field::part(input-field) {
border-radius: 8px;
}
コンポーネントスコープのスタイル — 特定のビューに CSS を適用します。
@StyleSheet("styles/views/dashboard-view.css")
@Route("dashboard")
public class DashboardView extends VerticalLayout {
// ...
}
重要な原則:CSS で値をハードコードするよりも、常にテーマのカスタムプロパティを優先してください。色、余白、サイズには、使用中のテーマのトークンを使います。これにより、スタイルのテーマとの一貫性が保たれ、ダークモードや密度の変更、将来のデザイン変更にも簡単に対応できます。
よくあるアンチパターン
- 色やサイズのハードコード — 常にテーマのカスタムプロパティを使用してください。値をハードコードするとダークモードが崩れ、テーマ設定もできなくなります。
- テーマプロパティではなくコンポーネントの内部実装を上書きする — 色がおかしい場合は、個々のコンポーネントの CSS ではなく、テーマの色トークンを上書きしてください。プロパティを 1 つ変更すれば、アプリ全体を更新できます。
- ビジュアルスタイルが多すぎる — カードのスタイルは 2~3 種類、テキストの階層は 2~3 段階、主要なアクションのスタイルは 1 種類に絞ってください。一貫性がプロフェッショナルな印象を生みます。
- テーマバリアントを無視する — カスタム CSS を書く前に、
ButtonVariant、GridVariant、TextFieldVariantなどを確認してください。必要なバリアントは、すでに用意されている可能性があります。 - サーバーでレンダリングされる更新に派手なアニメーションを使う — Vaadin はサーバーから再レンダリングされます。サーバープッシュのたびに複雑な登場アニメーションを使うと、動きがぎこちなくなります。アニメーションは初回のページ読み込みやユーザー操作による画面遷移に使用し、データ更新のたびには使わないでください。
- フラットなビジュアル階層 — すべてが同じように見えると、何も目立ちません。サイズ、太さ、色、エレベーションを使って、重要な要素に視線を誘導してください。
ベストプラクティス
- テーマプロパティから始める — まずテーマの基本プロパティをカスタマイズしてください。それだけで見た目を大きく変えられます。
- コンポーネントのテーマバリアントを使用する — プライマリー、ターシャリー、コンパクト、バッジのテーマなど、組み込みのものを使用してください。
- 一貫したカラー戦略を維持する — プライマリー/アクセントカラーを 1 色、追加の色を 1~2 色、ステータス用にセマンティックカラーを使用してください。
- エレベーションを考慮してデザインする — カード、ダイアログ、メニューには重なりを感じさせるデザインが必要です。テーマのエレベーションシステムを一貫して使用してください。
- モーションは控えめに追加する — ホバー時の CSS トランジション、ページ読み込み時のフェードイン、カードの段階的な表示などを使います。400ms 未満にしてください。
- ダークモードでテストする — 色をカスタマイズした場合は、ライトテーマとダークテーマの両方で確認してください。テーマプロパティを使えば、この確認を自動化できます。
詳細リファレンス
コンポーネントの ::part() セレクター、CSS アニメーションのレシピ、カラーパレットのレシピについては、references/design-patterns.md を参照してください。テーマトークンの完全な表については、aura-theme スキルの references/property-values.md(Aura)を参照するか、get_theme_css_properties(Aura、Lumo、または base)を呼び出してください。コンポーネントのテーマバリアントについては、get_component_styling を呼び出してください。