複数行の自由入力を受け付けるフォームコンポーネント。1行のText Inputと役割を分けるのは「入力量の予測」——どれくらい書かせるかをあらかじめ設計に落とし込むことが品質の分かれ道。
この記事を読むと、Text InputとTextareaの使い分け、自動リサイズ設計、文字数制限とバリデーションのA11y要件が自分でできるようになります。
1. UI例(Preview / Live)
実装で見る(GunjoUI)
この部品を、デザインシステム GUNJO の実装で確かめられます。
2. 定義(Definition)
複数行の自由テキスト入力を受け付ける <textarea> ベースのフォームコンポーネント。
Text Inputとの違い:Text Inputは「名前・メールアドレス・パスワード」のように1行で完結する短い入力向け。Textareaは「説明文・コメント・フィードバック」など、長文や改行を含む入力に使う。「何行になるか予測できない」場合は常に Textarea を選ぶ。
3. 使い分け(When to use / When NOT to use)
3.1 When to use
- コメント・フィードバック・説明文など、複数行になることが予測される自由入力
- 改行を含む入力(住所の詳細・備考など)
- ユーザーが自分のペースで長文を書くことが期待される場面
3.2 When NOT to use
- 名前・メールアドレス・パスワードなど1行で完結する入力(Text Input を使う)
- 定型の選択肢がある入力(Select / Radio / Checkbox を使う)
- コード入力・Markdown エディタなど特殊な入力(専用のエディタコンポーネントを使う)
3.3 代替UI(Alternatives)
- 1行の短い入力 →
Text Input - 構造化された選択 →
Select/Checkbox/Radio - リッチテキスト・コード入力 → 専用エディタコンポーネント
4. 設計判断の核(Decision Principles)
「何行書かせるか」を先に決める——高さ・リサイズ・文字数の3点セットが Textarea 設計の核心。
判断の優先順位:① 入力量の予測 → ② 初期高さ(rows)の設定 → ③ リサイズ可否 → ④ 文字数制限
rows属性で「だいたいこれくらい書いてほしい」という期待量を示す。短めの入力なら3〜4行、長文なら6〜8行が目安- 自動リサイズ(Auto-resize)は「入力量が予測できない場合」に採用し、最大高さを設定して画面を崩さない
- 文字数制限がある場合は、超える前(残り20〜30文字)から警告色でカウントダウンを始め、超えた瞬間にエラー表示する
- プレースホルダーは「例」を示す用途に使い、必須説明文をプレースホルダーだけに置かない(フォーカス時に消えるため)
5. 状態設計(States)
5.1 必須状態(Required)
- Default:入力可能な状態。ボーダーで入力領域が明確に分かること
- Focus:ボーダー色変化+フォーカスリング。キーボードユーザーにも位置が明確
- Error:バリデーション失敗。ボーダーが赤くなり、エラーメッセージが Textarea 直下に表示される
- Disabled:操作不可。背景をグレーに、
cursor-not-allowed
5.2 条件付き状態(Conditional)
- Filled:文字が入力された状態。文字数カウンターが動的に更新される
- Warning(文字数近接):残り文字数が少なくなったときに警告色(アンバー)でカウンターを強調
- Readonly:表示専用。ボーダーを薄くし編集不可を示す
5.3 State Gallery
| 状態 | 必須 | 何を伝えるか |
|---|---|---|
| Default | ✅ | 入力できること、入力領域の範囲 |
| Focus | ✅ | 今ここにフォーカスがあり、入力中であること |
| Error | ✅ | 入力内容に問題があり、何を修正すべきか |
| Disabled | ✅ | 現在この入力欄は使えないこと |
| Filled | — | 入力済みの文字量と残り文字数 |
| Warning | — | 文字数制限に近づいており、注意が必要なこと |
| Readonly | — | 参照専用で編集できないこと |
6. バリエーション設計(Variants)
Textarea のバリアントは主に「高さの扱い」で設計が変わる。
| バリアント | 目的 |
|---|---|
| Fixed Height | 固定行数(rows)。入力量が概ね予測できる場合 |
| Auto-resize | 入力に応じて高さが伸縮する。チャット入力欄・コメント欄に多い |
| Max-height + Scroll | Auto-resize に最大高さを設けて内部スクロールに切り替える |
| With Counter | 文字数制限がある場合のカウンター表示付き |
禁止パターン:resize: none をCSSで強制 → ユーザーが自分で大きさを調整できなくなる。縦方向のリサイズ(resize: vertical)は原則許容すること。
7. パターン集(Good / Bad / How to fix)
7.0 よく崩れる設計パターン(3つ)
- 1行Input で長文を要求:
<input type="text">に「300文字以内で入力」と書く → 入力量が見えず、横スクロールで読みにくい - 文字数オーバーを送信後に初めて伝える:フォーム送信まで制限を知らせない → ユーザーが書き直す手間が発生する
- エラーをプレースホルダーで伝える:フォーカスした瞬間にエラー説明が消えてしまい、何が問題か分からなくなる
7.1 Bad(典型3つ)
<input type="text">でコメント入力を実装し、rows の概念がなく入力量が見えない- 文字数制限を
maxlengthだけで実装 → 超えた瞬間に入力がロックされるが、ユーザーは何文字まで書けるか事前に分からない aria-describedbyがなく、エラーメッセージが視覚的には見えてもスクリーンリーダーに紐付かない
7.2 Good(対になる3つ)
- 複数行が予想される入力には Textarea を使い、
rowsで期待入力量を示す - 文字数カウンターを常に表示し、残り30文字でアンバー、超過で赤にリアルタイム変化させる
aria-describedby="error-id"でエラーメッセージと Textarea を関連付け、aria-invalid="true"を付与する
7.3 How to fix(手順)
- 入力欄に「何行分の入力が期待されるか」を決める →
rowsに設定する - 文字数制限がある場合、カウンターを Textarea 直下に常時表示し、
aria-live="polite"で動的更新をスクリーンリーダーに伝える - バリデーションエラーは
aria-invalid="true"とaria-describedbyでエラーメッセージを紐付ける resize: verticalを許容し、ユーザーが自分で高さを調整できるようにする
8. ルール(Must / Better)
Must(守らないと壊れる)
Better(品質が跳ねる)
9. アクセシビリティ要件(必須)
Keyboard
Tabでフォーカスでき、フォーカス後は通常テキスト入力が行えることShift + Tabで前の要素に戻れること
Focus
- フォーカスリングは周囲と4.5:1以上のコントラストを持つこと
- フォーカス時にプレースホルダーが消えても、
<label>は常に見える位置にあること
Screen Reader
<label for="id">と<textarea id="id">を関連付けて読み上げを確実にする- エラーメッセージは
aria-describedbyで紐付け、aria-invalid="true"を付与する - 文字数カウンターは
aria-live="polite"で動的更新を伝える
<!-- 基本パターン(文字数カウンター付き) -->
<label for="bio">自己紹介</label>
<textarea
id="bio"
aria-describedby="bio-counter bio-error"
aria-invalid="false"
rows="4"
></textarea>
<span id="bio-counter" aria-live="polite">残り 200 文字</span>
<span id="bio-error" role="alert"></span>
Touch / Pointer
- Textarea 自体のタップ領域はコンテンツ量に応じた高さで確保(最低 44px 以上の初期高さ)
- モバイルではソフトウェアキーボードが表示されたとき、Textarea が視野内に収まるようスクロール制御を考慮する
Contrast / Readability
- テキストと背景は4.5:1以上のコントラスト比を確保する
- プレースホルダーテキストは最低3:1のコントラスト比(WCAG 1.4.3)
10. 実装メモ(Implementation Notes)
- Auto-resize は CSS の
field-sizing: content(新仕様、Chrome 123+)または JavaScript でscrollHeightをもとにheightを動的設定する方法で実現できる。overflow: hiddenを組み合わせてスクロールバーを非表示にするのが基本パターン maxlength属性は「一定文字数を超えて入力できなくする」制限として使えるが、ユーザーが制限を知らないまま突然入力が止まる体験になるため、必ずカウンターと組み合わせる- React で制御コンポーネントとして使う場合、
valueとonChangeを必ずペアで渡す。defaultValueは非制御コンポーネント用
11. 関連リンク
- 関連するUIデザイン原則: フィードバック (Feedback), 明瞭性と確実性 (Clarity & Certainty), エラーから回復できる (Error Recovery)
- 用語集(定義): アクセシビリティ (Accessibility)
- 関連するUIコンポーネント(横): Text Input(テキスト入力), Button(ボタン)
12. まとめ
Textarea の設計は「何行書かせるか」を先に決めることから始まります。迷ったら 4. 設計判断の核 に戻り、rows・リサイズ可否・文字数制限の3点を確認してください。文字数制限があるなら、超える前からカウントダウンで伝えることがユーザビリティの核心です。エラー表示は aria-invalid と aria-describedby の組み合わせで、すべてのユーザーに正確に届けてください。