Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .Jules/palette.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,7 @@
## 2026-06-08 - Badge Snippet Accessible Names
**Learning:** アイコンやコピーなどの汎用的なアクションを実行するボタンが複数リストされている場合、スクリーンリーダーユーザーがどの項目のアクションかを識別できるように、`aria-label` に具体的なコンテキスト(例: `Copy ${snippet.label}`)を含めることが重要です。同時に、表示されているテキスト(この場合は 'Copy')を `aria-label` に含めることで WCAG 2.5.3(Label in Name)に準拠します。
**Action:** 今後、リスト内やコンテキストが不明瞭なボタン(特に同じテキストラベルを持つ複数のボタン)を実装・改善する際は、必ず `aria-label` に詳細な説明を含めるようにします。また、以前試みた「文字数カウンターの aria-live 属性の削除」は、スクリーンリーダーユーザーへのフィードバックを完全に奪うことになりアクセシビリティを低下させる(リグレッション)ため、行わないよう注意します。

## 2026-06-18 - Dynamic Form Validation Accessibility
**Learning:** フォーム内の動的なバリデーションステータス(例:スラッグの使用可能確認)を伝える際、入力フィールドに `aria-describedby` を設定してステータス要素と関連付け、ステータス要素自身に `aria-live="polite"` を付与することで、スクリーンリーダーユーザーが入力状態の変化を自然に把握できるようになります。また、フォーム送信エラーなど動的に出現するエラーメッセージ要素には `role="alert"` を付与することで、表示された瞬間にユーザーへ重要な通知として読み上げられます。
**Action:** 今後、非同期でステータスが更新される入力フィールドや動的なエラーメッセージを実装・改善する際は、`aria-describedby`、`aria-live="polite"`、`role="alert"` を適切に組み合わせてアクセシビリティを確保します。
13 changes: 11 additions & 2 deletions apps/web/src/app/collections/new/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -290,9 +290,14 @@ export default function NewCollectionPage() {
setSlug(e.target.value.toLowerCase().replace(/[^a-z0-9-]/g, ""));
}}
maxLength={40}
aria-describedby="slug-status"
className="w-full rounded-md border border-gray-300 px-3 py-2 text-sm dark:border-gray-700 dark:bg-gray-900"
Comment on lines 292 to 294

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

スラッグのバリデーション状態(invalid または taken)に応じて、入力フィールドに aria-invalid 属性を動的に付与することをおすすめします。

これにより、スクリーンリーダーなどの支援技術が、入力フィールドが現在エラー状態であることをユーザーに即座に伝えることができるようになり、アクセシビリティがさらに向上します。

            maxLength={40}
            aria-describedby="slug-status"
            aria-invalid={slugStatus === "invalid" || slugStatus === "taken" ? "true" : undefined}
            className="w-full rounded-md border border-gray-300 px-3 py-2 text-sm dark:border-gray-700 dark:bg-gray-900"

Comment on lines +293 to 294

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 aria-invalid が未設定のため、スラッグが「使用済み」または「無効」な状態でも入力フィールドがエラー状態であることをスクリーンリーダーに伝えられていません。aria-describedby でステータスメッセージは読み上げられますが、aria-invalid="true" がないと一部のスクリーンリーダーはフィールドがエラー状態であることを明示的にアナウンスしません(WCAG 1.3.1 / 4.1.2)。

Suggested change
aria-describedby="slug-status"
className="w-full rounded-md border border-gray-300 px-3 py-2 text-sm dark:border-gray-700 dark:bg-gray-900"
aria-describedby="slug-status"
aria-invalid={slugStatus === "taken" || slugStatus === "invalid"}
className="w-full rounded-md border border-gray-300 px-3 py-2 text-sm dark:border-gray-700 dark:bg-gray-900"
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/web/src/app/collections/new/page.tsx
Line: 293-294

Comment:
`aria-invalid` が未設定のため、スラッグが「使用済み」または「無効」な状態でも入力フィールドがエラー状態であることをスクリーンリーダーに伝えられていません。`aria-describedby` でステータスメッセージは読み上げられますが、`aria-invalid="true"` がないと一部のスクリーンリーダーはフィールドがエラー状態であることを明示的にアナウンスしません(WCAG 1.3.1 / 4.1.2)。

```suggestion
            aria-describedby="slug-status"
            aria-invalid={slugStatus === "taken" || slugStatus === "invalid"}
            className="w-full rounded-md border border-gray-300 px-3 py-2 text-sm dark:border-gray-700 dark:bg-gray-900"
```

How can I resolve this? If you propose a fix, please make it concise.

/>
<p className="text-xs mt-1 text-gray-500">
<p
id="slug-status"
aria-live="polite"
className="text-xs mt-1 text-gray-500"
>
{slugStatus === "checking" && "確認中..."}
{slugStatus === "available" && "✓ 使用可能"}
{slugStatus === "taken" && "✗ 使用済み"}
Expand Down Expand Up @@ -347,7 +352,11 @@ export default function NewCollectionPage() {
</select>
</div>

{error && <p className="text-sm text-red-600">{error}</p>}
{error && (
<p role="alert" className="text-sm text-red-600">
{error}
</p>
)}

<button
type="submit"
Expand Down
Loading