Skip to content

🎨 Palette: 動的フォーム検証のアクセシビリティ改善(Slug検証)#1025

Open
is0692vs wants to merge 2 commits into
stagingfrom
palette/a11y-slug-validation-3237905151982779644
Open

🎨 Palette: 動的フォーム検証のアクセシビリティ改善(Slug検証)#1025
is0692vs wants to merge 2 commits into
stagingfrom
palette/a11y-slug-validation-3237905151982779644

Conversation

@is0692vs

@is0692vs is0692vs commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

💡 What: collections/neworgs/new ページのスラッグ(URL識別子)入力フィールドにおいて、動的なバリデーションのステータス(「確認中...」「使用可能」「使用済み」など)に aria-describedbyaria-live="polite" を追加しました。

🎯 Why: 従来の実装では、スクリーンリーダーを使用するユーザーは、入力中に非同期で変化するスラッグの利用可能ステータスを即座に知ることができず、フォーカスを移動してステータステキストを個別に探す必要がありました。この変更により、ユーザーが入力を行っている間に、検証ステータスの変化が自然にアナウンスされるようになり、アクセシビリティが向上します。

📸 Before/After: 視覚的な変更はありません(HTMLの属性のみの追加です)。

Accessibility:

  • スラッグ入力フィールド (<input>) に aria-describedby="slug-status" を付与しました。
  • ステータスメッセージを内包する要素 (<p> または <div>) に id="slug-status"aria-live="polite" を追加し、動的な変更がスクリーンリーダーに伝わるようにしました。

PR created automatically by Jules for task 3237905151982779644 started by @is0692vs

Greptile Summary

このPRでは、collections/new および orgs/new ページのスラッグ入力フィールドに aria-describedby=\"slug-status\" を付与し、対応するステータス表示要素(<p> / <div>)に id=\"slug-status\"aria-live=\"polite\" を追加することで、スクリーンリーダー向けアクセシビリティを改善します。

  • collections/new/page.tsx: スラッグ <input>aria-describedby を、ステータス <p>idaria-live=\"polite\" を追加。
  • orgs/new/page.tsx: 同様に <input>aria-describedby を、ステータス <div>idaria-live=\"polite\" を追加。
  • .Jules/palette.md: 今回の改善内容をチームの学習ログとして記録。

Confidence Score: 4/5

HTMLの属性追加のみでロジックへの変更はなく、アクセシビリティ改善として有益な変更です。マージ自体のリスクは低いです。

aria-live="polite"aria-atomic="true" が設定されていないため、一部のスクリーンリーダーではステータスメッセージの部分テキストのみがアナウンスされる可能性があります。実害は限定的ですが、改善の余地があります。

両ページファイルで aria-atomic="true" の追加を検討することを推奨します。

Important Files Changed

Filename Overview
apps/web/src/app/collections/new/page.tsx スラッグ入力に aria-describedby を追加し、ステータス

に id="slug-status" と aria-live="polite" を付与。role="status" の利用を検討する余地がある。

apps/web/src/app/orgs/new/page.tsx 同様に aria-describedby + aria-live="polite" を追加。collections ページと実装が統一されている。
.Jules/palette.md チームの学習ログに今回のアクセシビリティ改善を追記。コードへの影響なし。

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant U as ユーザー
    participant I as input要素
    participant L as ライブリージョン
    participant API as サーバー

    U->>I: フォーカス
    I-->>U: ラベル+aria-describedbyの現在の内容を読み上げ
    U->>I: テキスト入力
    I->>L: "slugStatus=checking に更新"
    L-->>U: aria-liveにより「確認中...」をアナウンス
    I->>API: スラッグ利用可否を非同期確認
    API-->>I: 結果返却
    I->>L: "slugStatus=available/taken に更新"
    L-->>U: aria-liveにより「使用可能」または「使用済み」をアナウンス
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant U as ユーザー
    participant I as input要素
    participant L as ライブリージョン
    participant API as サーバー

    U->>I: フォーカス
    I-->>U: ラベル+aria-describedbyの現在の内容を読み上げ
    U->>I: テキスト入力
    I->>L: "slugStatus=checking に更新"
    L-->>U: aria-liveにより「確認中...」をアナウンス
    I->>API: スラッグ利用可否を非同期確認
    API-->>I: 結果返却
    I->>L: "slugStatus=available/taken に更新"
    L-->>U: aria-liveにより「使用可能」または「使用済み」をアナウンス
Loading
Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
apps/web/src/app/collections/new/page.tsx:296
`aria-live="polite"` の代わりに `role="status"` を使用することを検討してください。`role="status"` は暗黙的に `aria-live="polite"``aria-atomic="true"` の両方を設定するため、ステータスメッセージが部分更新されず常に全文がアナウンスされることが保証されます。また、要素の意味(「ステータスメッセージ」)もセマンティックに伝わります。

```suggestion
          <p id="slug-status" role="status" aria-live="polite" aria-atomic="true" className="text-xs mt-1 text-gray-500">
```

### Issue 2 of 2
apps/web/src/app/orgs/new/page.tsx:191
`collections/new` と同様に、`role="status"``aria-atomic="true"` の追加を検討してください。スクリーンリーダーによっては `aria-live="polite"` のみでは変更された部分テキストのみをアナウンスする場合があり、`aria-atomic="true"` によりステータス全体が一貫して読み上げられます。

```suggestion
          <div id="slug-status" role="status" aria-live="polite" aria-atomic="true" className="mt-1">
```

Reviews (1): Last reviewed commit: "feat(web): add aria-describedby and aria..." | Re-trigger Greptile

Greptile also left 2 inline comments on this PR.

is0692vs and others added 2 commits June 25, 2026 11:37
Release: staging -> main (2026-06-24 15:53)
This adds `aria-describedby` and `aria-live="polite"` to the slug validation
status elements on the collection creation and organization creation pages,
allowing screen readers to announce the availability status dynamically.

Co-authored-by: is0692vs <135803462+is0692vs@users.noreply.github.com>
@google-labs-jules

Copy link
Copy Markdown
Contributor

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@vercel

vercel Bot commented Jun 25, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
open-shelf Ignored Ignored Jun 25, 2026 3:14pm

@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@dosubot dosubot Bot added the enhancement New feature or request label Jun 25, 2026
@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@is0692vs, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 50 minutes and 45 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more credits in the billing tab to continue.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 92a10d4d-f234-468d-a103-145697989660

📥 Commits

Reviewing files that changed from the base of the PR and between f00bd68 and 7320b1f.

📒 Files selected for processing (3)
  • .Jules/palette.md
  • apps/web/src/app/collections/new/page.tsx
  • apps/web/src/app/orgs/new/page.tsx
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch palette/a11y-slug-validation-3237905151982779644

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot changed the base branch from main to staging June 25, 2026 15:15
@github-actions

Copy link
Copy Markdown

このリポジトリでは staging 先行フローを採用しています。PR のターゲットを staging に変更しました。staging で動作確認後、stagingmain の PR を作成してください。

@codecov

codecov Bot commented Jun 25, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

@gemini-code-assist gemini-code-assist Bot left a comment

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.

Code Review

This pull request improves accessibility for dynamic form validation on the new collection and new organization pages by adding aria-describedby and aria-live="polite" attributes to the slug input and status elements, as documented in the updated .Jules/palette.md. The reviewer provided feedback to further enhance accessibility and visual design, suggesting status-specific text colors with dark mode support for the status messages, and recommending updating text content directly inside the aria-live container to ensure reliable screen reader announcements.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

className="w-full rounded-md border border-gray-300 px-3 py-2 text-sm dark:border-gray-700 dark:bg-gray-900"
/>
<p className="text-xs mt-1 text-gray-500">
<p id="slug-status" aria-live="polite" className="text-xs mt-1 text-gray-500">

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

💡 改善の提案:ステータスに応じた文字色の適用とダークモード対応

現在、スラッグの検証ステータス(「使用可能」「使用済み」など)がすべて text-gray-500 で表示されています。
ユーザーが視覚的にも直感的にステータスを理解できるように、orgs/new/page.tsx と同様にステータスに応じた色(使用可能なら緑、エラー/使用済みなら赤)を適用することをお勧めします。

また、ダークモード時のコントラスト比を考慮し、dark:text-green-400dark:text-red-400 を指定することで、WCAGのコントラスト基準を満たすアクセシブルな配色に改善できます。

Suggested change
<p id="slug-status" aria-live="polite" className="text-xs mt-1 text-gray-500">
<p
id="slug-status"
aria-live="polite"
className={
"text-xs mt-1 " +
(slugStatus === "available"
? "text-green-600 dark:text-green-400"
: slugStatus === "taken" || slugStatus === "invalid"
? "text-red-600 dark:text-red-400"
: "text-gray-500 dark:text-gray-400")
}
>

Comment on lines +191 to +193
<div id="slug-status" aria-live="polite" className="mt-1">
{slugStatusText()}
</div>

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

💡 改善の提案:アクセシビリティの向上、ダークモード対応、および実装の共通化

現在の実装では、slugStatusText() が返す <span> 要素を動的に挿入/削除していますが、一部のスクリーンリーダーでは aria-live 領域内のDOM要素の追加・削除を正しく検知できない場合があります。
コンテナ要素(div)のテキストコンテンツのみを直接更新するように変更することで、より確実にアナウンスされるようになります。

また、以下の改善も同時に行えます:

  1. ダークモード対応: text-green-600text-red-600 はダークモードの背景でコントラストが低く見づらいため、dark:text-green-400dark:text-red-400 を追加して視認性を向上させます。
  2. 実装の共通化: collections/new/page.tsx と同様のインライン条件分岐に統一することで、コードの可読性と一貫性が向上します。

※ この変更を適用した後、不要になった slugStatusText 関数(121〜138行目)は削除してください。

Suggested change
<div id="slug-status" aria-live="polite" className="mt-1">
{slugStatusText()}
</div>
<div
id="slug-status"
aria-live="polite"
className={
"text-xs mt-1 " +
(slugStatus === "available"
? "text-green-600 dark:text-green-400"
: slugStatus === "taken" || slugStatus === "invalid"
? "text-red-600 dark:text-red-400"
: "text-gray-400 dark:text-gray-500")
}
>
{slugStatus === "checking" && "確認中..."}
{slugStatus === "available" && "✓ 使用可能"}
{slugStatus === "taken" && "✗ 使用済み"}
{slugStatus === "invalid" && "※ 3〜40文字、英小文字・数字・ハイフンのみ"}
</div>

className="w-full rounded-md border border-gray-300 px-3 py-2 text-sm dark:border-gray-700 dark:bg-gray-900"
/>
<p className="text-xs mt-1 text-gray-500">
<p id="slug-status" aria-live="polite" className="text-xs mt-1 text-gray-500">

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-live="polite" の代わりに role="status" を使用することを検討してください。role="status" は暗黙的に aria-live="polite"aria-atomic="true" の両方を設定するため、ステータスメッセージが部分更新されず常に全文がアナウンスされることが保証されます。また、要素の意味(「ステータスメッセージ」)もセマンティックに伝わります。

Suggested change
<p id="slug-status" aria-live="polite" className="text-xs mt-1 text-gray-500">
<p id="slug-status" role="status" aria-live="polite" aria-atomic="true" className="text-xs mt-1 text-gray-500">
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/web/src/app/collections/new/page.tsx
Line: 296

Comment:
`aria-live="polite"` の代わりに `role="status"` を使用することを検討してください。`role="status"` は暗黙的に `aria-live="polite"``aria-atomic="true"` の両方を設定するため、ステータスメッセージが部分更新されず常に全文がアナウンスされることが保証されます。また、要素の意味(「ステータスメッセージ」)もセマンティックに伝わります。

```suggestion
          <p id="slug-status" role="status" aria-live="polite" aria-atomic="true" className="text-xs mt-1 text-gray-500">
```

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

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

/>
</div>
<div className="mt-1">{slugStatusText()}</div>
<div id="slug-status" aria-live="polite" className="mt-1">

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 collections/new と同様に、role="status"aria-atomic="true" の追加を検討してください。スクリーンリーダーによっては aria-live="polite" のみでは変更された部分テキストのみをアナウンスする場合があり、aria-atomic="true" によりステータス全体が一貫して読み上げられます。

Suggested change
<div id="slug-status" aria-live="polite" className="mt-1">
<div id="slug-status" role="status" aria-live="polite" aria-atomic="true" className="mt-1">
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/web/src/app/orgs/new/page.tsx
Line: 191

Comment:
`collections/new` と同様に、`role="status"``aria-atomic="true"` の追加を検討してください。スクリーンリーダーによっては `aria-live="polite"` のみでは変更された部分テキストのみをアナウンスする場合があり、`aria-atomic="true"` によりステータス全体が一貫して読み上げられます。

```suggestion
          <div id="slug-status" role="status" aria-live="polite" aria-atomic="true" className="mt-1">
```

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

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request size/S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant