frontend-ux について
Web3 フロントエンド開発者向けの UX ルールガイドです。オンチェーン操作の状態、アドレスと金額の表示、RPC の利用、エラー通知を扱います。
主な機能
- 01トランザクションごとの処理中状態
- 02接続・ネットワーク・承認に応じた操作順
- 03アドレスの検証・コピー・表示
- 04トークン額のドル換算表示
- 05コントラクトエラーとテーマスタイルへの対応
活用シーン
- 01承認やトランザクションボタンの状態表示改善
- 02ウォレットアドレス入力と表示の設計
- 03フロントエンドの RPC ポーリング問題の調査
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ austintgriffith/ ethskills --skill frontend-uxインストール後、Claude Code で/frontend-uxを入力して読み込まれたか確認します。
詳細
フロントエンド UX ルール
よくある間違い
「ボタンは動作します。」 クリックできるだけでは不十分です。クリックしたらすぐに無効化し、保留中であることを明確に示し、オンチェーンでの確認が完了するまで無効のままにする必要があります。
「アドレスはただの文字列です。」 アドレスの UX には、検証、安全な表示形式、コピー機能、エクスプローラーへのリンク、利用可能な場合の ENS/名前解決が必要です。
「トークンの数量は分かりやすいです。」 USD の文脈を伴わないトークンの生の値では、ユーザーはリスクや価値を推測しなければなりません。数量が重要な箇所には、すべてドル換算額を表示してください。
ルール 1:オンチェーン操作を行う各ボタンには、それぞれ独自の保留状態が必要です
オンチェーントランザクションを実行するボタンは、すべて次のようにする必要があります。
- クリックしたらすぐに無効化する
- スピナーと操作テキスト(
Approving...、Staking...)を表示する - チェーンの状態で完了が確認されるまで無効のままにする
- 完了時に成功/エラーのフィードバックを表示する
// Separate loading state per action
const [isApproving, setIsApproving] = useState(false);
const [isStaking, setIsStaking] = useState(false);
<button
disabled={isApproving}
onClick={async () => {
setIsApproving(true);
try {
await sendApproveTx();
} catch (e) {
notifyError("Approval failed");
} finally {
setIsApproving(false); // always release — even on rejection
}
}}
>
{isApproving ? "Approving..." : "Approve"}
</button>
複数のボタンで共通の isLoading 状態を使わないでください。ラベルや無効状態が誤って表示され、送信が重複する原因になります。
承認フローでは、isPending だけでは不十分です。
ウォレットからトランザクションハッシュが返されると、オンチェーンで確認される前に isPending は false になります。isPending = false なのに allowance が更新されていない時間が発生し、処理の途中でボタンが再び有効になって、ユーザーが二重送信できてしまう可能性があります。
承認ハンドラーには、2 つの状態が必要です。approvalSubmitting はクリック時に設定し、finally {} で解除して、ウォレットから確認までの間をカバーします。approveCooldown は確認後に設定し、4 秒後に再取得してから解除して、確認からキャッシュ更新までの間をカバーします。どちらも disabled に指定してください。finally {} は必須です。これがないと、トランザクションが拒否された場合にボタンが永久にロックされます。
ルール 2:4 つの状態からなるアクションフロー
一度に表示する主要なアクションは 1 つにしてください。
1. Not connected -> Connect Wallet
2. Wrong network -> Switch Network
3. Needs approval -> Approve
4. Ready -> Execute action (Stake/Deposit/Swap/etc.)
重要な詳細:
- ネットワークの不一致チェックは、承認/アクションのチェックより先に行う必要があります
- Approve と Execute を同時に表示しないでください
- 承認状態は、新しいオンチェーン状態から取得する必要があります(古いローカル状態だけに依存しないでください)
- 接続状態では、受動的なテキストではなく、クリックできるアクションを表示する必要があります
ルール 3:アドレスの UX 基準
表示するすべてのアドレスで、次の操作をサポートしてください。
- ENS/名前解決(該当する場合)
- エクスプローラーへのリンク
- クリップボードへのコピー
- 安全な省略表示と視覚的な識別(アバター/ブロッキーは任意)
すべてのアドレス入力で、次の操作をサポートしてください。
- 検証
- 貼り付け時の正規化
- 利用可能な場合の ENS/名前解決
UI キットにアドレス専用のコンポーネントが含まれている場合は、それを使用してください。重要なアドレスの入力に、通常の自由入力フィールドを使用しないでください。
ルール 4:トークン値に USD の文脈を表示する
ユーザーに表示するトークン/ETH の数量には、すべて USD の文脈を含めてください。
- 残高
- 入力値(リアルタイムプレビュー)
- 確認テキスト
- ポジション/ポートフォリオの概要
<span>0.5 ETH (~$1,250.00)</span>
<span>1,000 TOKEN (~$4.20)</span>
トークン単位の数量だけを表示し、価値の文脈を示さないことは避けてください。
ルール 5:RPC の信頼性とポーリング
- 本番環境では専用の RPC プロバイダーを使用してください(意図せずパブリックフォールバックだけに依存しないでください)
- ポーリング間隔は応答性の高い範囲に保ってください(インタラクティブなアプリでは通常、約 2~5 秒)
- フォールバックのトランスポートは意図して設定し、レート制限を考慮してください
- 過剰なリクエストが発生するパターン(レンダリングループ、監視処理の重複、上限のないポーリング)に注意してください
健全な基準は、リクエスト量が少なく安定していることです。QPS が急増したり、高い状態が続いたりする場合、通常はフロントエンドのフック/設定に問題があります。
ルール 6:ハードコードしたダークラッパーではなく、テーマの意味論を使う
テーマ/システム設定を無視して、ページ全体の暗い背景をハードコードしないでください。
意味を持つテーマトークン/クラスを使用し、ライトモード/ダークモードで次の要素の一貫性を保ってください。
- ページの背景
- サーフェスのレイヤー
- プライマリ/セカンダリテキスト
- コンポーネントの状態
ダークモードのみで意図的に提供する場合は、適用されなくなったテーマコントロールを削除するか、無効にしてください。
ルール 7:コントラクトエラーの翻訳
ユーザーに、生の revert セレクターを表示したり、何も通知せずに失敗したりしてはなりません。
次を実装してください。
- ABI/カスタムエラーからのエラー抽出
- 人間が理解できるメッセージへのマッピング
- ウォレットレベルのエラー処理(拒否、ガスの問題)
- 安全なフォールバックメッセージ
- アクションの実行箇所近くに表示する、インラインの永続的なエラー UI
try {
await sendTx();
} catch (e) {
setTxError(parseContractError(e));
}
ルール 8:公開前のメタデータとプロダクトのアイデンティティ
本番リリース前に、以下を確認してください。
- Open Graph 画像の URL が絶対 URL で、公開ドメイン(
https://...)からアクセスできる - OG/Twitter のタイトルと説明が正しく設定されている
- ソーシャルプレビュー画像が有効で、ローカルパスや相対パスではない
- テンプレートのデフォルトのブランディングが削除されているか、プロジェクトのアイデンティティに置き換えられている
- ファビコンとタブのタイトルがアプリを反映している
ルール 9:人が読みやすい金額と小数
コントラクト単位と表示単位の間で、必ず変換してください。
import { formatEther, formatUnits, parseEther, parseUnits } from "viem";
formatEther(weiAmount);
formatUnits(tokenAmount, tokenDecimals);
parseEther("1.5");
parseUnits("100", 6); // USDC-style 6 decimals
1500000000000000000 のような基準単位の生の値は、決して表示しないでください。
完了する前に、feedback/SKILL.md から、問題点または称賛を一行で送信してください。