Input group
アイコン、テキスト、ボタン、キーボードのヒントを付けられる入力欄です。1つのボーダーとフォーカスリングを共有します。
pnpm dlx shadcn@latest add https://hextaui.com/r/input-group.jsonコンポーネント、HextaUIのテーマトークン、依存するHextaUIコンポーネントを追加します。
まだ追加していない場合は、グローバルCSSにテーマトークンを追加してください。
依存関係をインストールします。
pnpm add @base-ui/react @tabler/icons-react class-variance-authority cn次のコードをコピーしてプロジェクトに貼り付けてください。
components/ui/input-group.tsx components/ui/input.tsx components/ui/button.tsx components/ui/number-flow.tsx lib/motion.ts インポートパスは、お使いのプロジェクト構成に合わせて更新してください。
<InputGroupInput /> または <InputGroupTextarea /> を先に置き、その後にアドオンを置きます。アドオンは align で自分の位置を決めるため、フィールドがタブ順とスクリーンリーダーの両方で先頭になります。
グループは自分のフィールドを追跡するため、スマートなパーツには配線が不要です。<InputGroupClear />、<InputGroupPasswordToggle />、<InputGroupCount /> は、制御されているかどうかにかかわらず、フィールドから value、type、maxLength を読み取ります。
アイコン
アイコンは、両側の枠線の内側に配置されます。アイコンをクリックすると入力欄にフォーカスするため、グループ全体が 1 つのフィールドのように感じられます。
クリア
<InputGroupClear /> は、値があるとフェードインします。ブラウザの編集履歴を通じてクリアするため、Cmd+Z でテキストが戻り、onChange も発火します。Escape でもクリアされます。2 回目の Escape は、周囲のダイアログやポップオーバーに残されます。
文字数
<InputGroupCount /> は、フィールドの maxLength に対する文字数を数えます。変化した桁だけが回転します。上限に近づくと数字が濃くなり、上限に達すると赤くなり、上限を超えて入力したキーはカウンターを揺らします。スクリーンリーダーには、フィールドが上限に近づいたときと到達したときにメッセージが読み上げられ、すべてのキー入力で読み上げられることはありません。
テキスト
単位、通貨、URL の一部には <InputGroupText /> を使います。入力欄のパディングはアドオンの隣で小さくなるため、テキストは 1 つの値として読めます。
Button
<InputGroupButton /> は、フィールドの内側に収まるサイズの ghost ボタンです。角丸はグループと同心で、独自のフォーカスリングを持ちます。
キーボードのヒント
アドオン内のプレーンな <kbd> は、キーキャップとしてスタイルされます。視覚的なヒントにすぎないため、ショートカットのバインドは自分で行ってください。
Textarea
<InputGroupTextarea /> は、コンテンツに合わせて 16rem まで大きくなり、その後はスクロールします。高さは、跳ねずに行ごとにイージングします。block-end のアドオンはその下のツールバーになり、端にあるボタンには、置かれた角と同じインセットが付きます。
ヘッダー
block-start のアドオンは、フィールドの上に配置されます。間に細い線を描画するには separator を追加します。
パスワード
<InputGroupPasswordToggle /> は、type="password" のフィールドをテキストに切り替え、元に戻します。キャレットと選択範囲はそのまま保たれ、マウスでクリックしてもフォーカスはフィールドに残り、フォームの送信時にパスワードは再び隠されます。revealed で制御できます。
サイズ
グループの size は高さを設定し、<Input /> のサイズに合わせて入力欄に引き継がれます。ボタンはどのサイズでも同心の角を保ちます。
無効な値
入力欄に aria-invalid を設定すると、フォーカスリングを含めてグループ全体が赤くなります。メッセージは aria-describedby で関連付けます。
無効
入力欄が無効な場合、グループ全体が暗くなり、その上で not-allowed カーソルが表示されます。アドオンのボタンはそのままでは使えてしまうため、あわせて無効にしてください。
読み込み中
インラインのアドオンは、内容が変わると新しい幅にイージングするため、スピナーが結果の件数に変わっても、フィールドが跳ねることはありません。スピナーはモーションが許可されている場合にのみ回転し、role="status" がテキストを通知します。
Dropdown
<InputGroupButton /> をドロップダウンのトリガーとしてレンダリングすると、入力の範囲を絞り込めます。
長いコンテンツ
長い値はグループを広げず、入力欄の中でスクロールします。長いアドオンのテキストは、最大幅を指定した省略用の span で囲みます。
右から左
アドオン、パディング、角丸は論理的な側を使うため、inline-start は右側になります。
| キー | アクション |
|---|---|
| Tab | フィールドから各アドオンのボタンへ、ソースの順に移動します。 |
| ShiftTab | ボタンとフィールドを逆順に移動します。 |
| Escape | InputGroupClear がある場合は、フィールドをクリアします。すでに空の場合、Escape はそのまま通過します。 |
- すべてのフィールドには名前が必要です。表示されるラベル、Field、または
aria-labelを使ってください。アイコンとアドオンのテキストは、フィールドの名前には含まれません。 - アイコンのみのボタンには
aria-labelを付けてください。 - 通貨やドメインのように、アドオンのテキストに意味がある場合は、ラベルに含めるか、
aria-describedbyで参照してください。 - Escape が同じ動作をするため、
<InputGroupClear />はタブ順からスキップされます。パスワードの切り替えボタンはタブで移動でき、同じ名前を保ち、aria-pressedが状態を伝えます。 - 送信時にフィールドが無効と判定されると、グループは 1 回揺れます。モーションの低減が有効な場合は、赤い枠線が唯一の手がかりです。
- タッチスクリーンでは、フォーカス時にスマートフォンがズームしないよう、フィールドのテキストは 16px 以上になります。
<InputGroupInput /> と <InputGroupTextarea /> は、レンダリングする要素の props を受け付けます。それ以外のパーツは、その要素の属性を受け付けます。
| プロパティ | 型 | デフォルト |
|---|---|---|
size入力欄に引き継がれる、グループの高さ。 | "sm" | "default" | "lg" | "default" |
| 属性 | 説明 |
|---|---|
data-slot="input-group" | CSS でグループを指定します。role="group" をレンダリングします。 |
data-size | 現在のサイズ。 |
data-filled | フィールドに値がある間、付与されます。 |
data-shake | 送信に失敗した後、グループが揺れている間、付与されます。 |
data-disabled | アドオンだけが無効な場合にグループを暗くしたいときは、自分で設定します。 |
--input-group-radius | グループの角丸の半径。ボタンとキーキャップはこれから角丸を算出します。 |
--input-group-height | 現在のサイズに対応するグループの高さ。 |
| プロパティ | 型 | デフォルト |
|---|---|---|
sizeグループから継承されます。 | "sm" | "default" | "lg" | – |
aria-invalid | boolean | – |
disabled | boolean | false |
readOnly | boolean | false |
| 属性 | 説明 |
|---|---|
data-slot="input-group-control" | フィールドをマークします。グループは、フォーカス、不正、無効、読み取り専用の状態をここから読み取ります。 |
data-invalid | 周囲の Field が値を不正とマークしたときに付与されます。 |
data-disabled | フィールドが無効なときに付与されます。 |
data-focused | フィールドにフォーカスがある間、付与されます。 |
data-filled | フィールドに値があるときに付与されます。 |
data-dirty | 値が初期値と異なるときに付与されます。 |
data-touched | フィールドがフォーカスされて離れた後に付与されます。 |
| プロパティ | 型 | デフォルト |
|---|---|---|
autoResizeコンテンツに合わせて 16rem まで大きくなり、高さの間をイージングします。 | boolean | true |
shake送信時に無効と判定された場合、グループを揺らします。 | boolean | true |
rows | number | – |
aria-invalid | boolean | – |
disabled | boolean | false |
| 属性 | 説明 |
|---|---|
data-slot="input-group-control" | フィールドをマークします。グループは、フォーカス、不正、無効、読み取り専用の状態をここから読み取ります。 |
data-invalid | 周囲の Field が値を不正とマークしたときに付与されます。 |
data-disabled | フィールドが無効なときに付与されます。 |
data-focused | フィールドにフォーカスがある間、付与されます。 |
data-filled | フィールドに値があるときに付与されます。 |
data-dirty | 値が初期値と異なるときに付与されます。 |
data-touched | フィールドがフォーカスされて離れた後に付与されます。 |
| プロパティ | 型 | デフォルト |
|---|---|---|
align | "inline-start" | "inline-end" | "block-start" | "block-end" | "inline-start" |
separatorブロックのアドオンとフィールドの間に細い線を描画します。 | boolean | false |
| 属性 | 説明 |
|---|---|
data-slot="input-group-addon" | CSS でアドオンを指定します。 |
data-align | 現在の配置。 |
data-separator | separator が設定されているときに付与されます。 |
--input-group-addon-inset | グループの端と、内側のボタンやキーキャップとの間の空間。 |
| プロパティ | 型 | デフォルト |
|---|---|---|
variant | "default" | "outline" | "secondary" | "ghost" | "destructive" | "link" | "ghost" |
size | "xs" | "sm" | "icon-xs" | "icon-sm" | "xs" |
type | string | "button" |
feedback読み込みと成功のフローを含め、Button のすべての props が使えます。 | boolean | false |
| 属性 | 説明 |
|---|---|
data-slot="input-group-button" | CSS でアドオンのボタンを指定します。 |
data-size | 現在のサイズ。 |
| プロパティ | 型 | デフォルト |
|---|---|---|
onClearフィールドがクリアされた後に呼ばれます。 | () => void | – |
aria-label | string | "Clear" |
children | ReactNode | <IconX /> |
| 属性 | 説明 |
|---|---|
data-slot="input-group-clear" | CSS でクリアボタンを指定します。 |
data-visible | フィールドに値があり、編集可能な間、付与されます。 |
| プロパティ | 型 | デフォルト |
|---|---|---|
revealed制御された state。自動で管理させるには、未設定のままにします。 | boolean | – |
onRevealedChange | (revealed: boolean) => void | – |
aria-label | string | "Show password" |
| 属性 | 説明 |
|---|---|
data-slot="input-group-password-toggle" | CSS で切り替えボタンを指定します。 |
data-revealed | パスワードが表示されている間、付与されます。 |
| プロパティ | 型 | デフォルト |
|---|---|---|
thresholdカウントが目立ち始める時点での残り文字数。 | number | 10% of maxLength, at most 20 |
announcement文字数がしきい値を超えたとき、または上限に達したときの、スクリーンリーダー向けのメッセージ。 | (remaining: number) => string | – |
| 属性 | 説明 |
|---|---|
data-slot="input-group-count" | CSSでカウントを指定します。 |
data-state="near" | "limit" | しきい値内、および残り文字数がなくなったときに付与されます。 |
data-bump | 上限でキーが押されたときに、短時間付与されます。 |
| 属性 | 説明 |
|---|---|
data-slot="input-group-text" | CSS でアドオンのテキストを指定します。 |
- Buttonすべてのバリアントとサイズのボタンです。読み込み、成功、エラーのフローを内蔵し、高速なリクエストではスピナーを省略します。
- Input3つのサイズ、無効状態と読み取り専用状態、ネイティブのバリデーションスタイル、スマートフォンでズームされない16pxのタッチ用フォントを備えたテキスト入力です。
- Motionすべてのコンポーネントがアニメーションに使うイージングカーブ、継続時間、モーション軽減のチェックと、サイズのモーフィングやスライドするハイライト用のフックです。
- useAutosizeテキストエリアを、書いた内容に合わせて最小の高さと最大の高さの間で伸ばします。変化ごとにアニメーションしますが、テキストには一切触れません。
- useComposedRef自分の要素へのrefを保持しつつ、親から渡されたrefにもそのまま転送します。
- useInvalidShake送信を試みて無効だったとき、フォームコントロールを揺らします。入力中は揺らしません。
使用しているブロック
Input group の上に構築されるブロック。
- BillingCursor、Claude、Vercelのスタイルによる、AIプロダクト向けのプランと使用量です。モデルごとに分かれ、サイクル終了時を予測してクレジット切れの前に警告する使用量メーター、ドラッグで確認できる日別チャート、メーター上でプレビューできるアラートつきの支出上限、正確な日割り計算によるプラン変更、実際のバリデーションを備えたカードフォーム、PDFでダウンロードできる請求書を備えています。
- Diff Reviewエージェントによる編集を、反映される前にファイルをまたいで確認します。件数つきのファイルツリー、変更ごと、ファイルごと、またはすべてに対する承認と却下、任意の行や範囲に付けてエージェントへ返せるコメント、ユニファイドビューとスプリットビュー、単語単位のハイライト、取り消し、ストリーミングされる編集、チャット向けの「Edited 4 files」サマリーを備えています。
- ModelsAIプロダクトの設定にあるモデルページです。コンテキスト、速度、コストが一目でわかるデフォルトモデル、各モデルが対応する内容を把握しているデフォルトの推論量、フィルター、ピン留め、一括切り替えを備えプロバイダーごとにグループ化された検索可能なモデルリスト、実際の接続テストができるOpenAI互換サーバー、新着を知らせる更新を備えています。
- ProfileAIプロダクトの設定にあるプロフィールセクションです。写真を円形に切り抜き、入力しながら確認されるユーザー名を選び、6桁のコードで新しいメールアドレスを確認し、サイトを認識するリンクを追加し、他の人からどう見えるかをライブのカードで確認できます。