HextaUI

useInvalidShake

送信を試みて無効だったとき、フォームコントロールを揺らします。入力中は揺らしません。

Submit without choosing.
"use client"

import * as React from "react"

import { Button } from "@/components/ui/button"
import { useInvalidShake } from "@/hooks/use-invalid-shake"

export function UseInvalidShakeDemo() {
  const ref = React.useRef<HTMLSelectElement>(null)
  const [sent, setSent] = React.useState<string>()
  useInvalidShake(ref)

  return (
    <form
      className="flex w-full max-w-xs flex-col gap-3"
      onSubmit={(event) => {
        event.preventDefault()
        setSent(String(new FormData(event.currentTarget).get("plan")))
      }}
    >
      <label className="flex flex-col gap-2 text-sm font-medium">
        Plan
        <select
          ref={ref}
          name="plan"
          required
          defaultValue=""
          className="h-9 rounded-md bg-muted px-2.5 text-sm font-normal outline-none focus-visible:ring-3 focus-visible:ring-focus-ring focus-visible:outline-hidden data-shake:motion-safe:animate-button-shake pointer-coarse:text-touch [&:user-invalid]:ring-2 [&:user-invalid]:ring-destructive/40"
        >
          <option value="" disabled>
            Choose a plan
          </option>
          <option value="hobby">Hobby</option>
          <option value="pro">Pro</option>
        </select>
      </label>
      <Button type="submit" size="sm">
        Continue
      </Button>
      <output className="text-sm text-muted-foreground">
        {sent ? `plan=${sent}` : "Submit without choosing."}
      </output>
    </form>
  )
}
pnpm dlx shadcn@latest add https://hextaui.com/r/use-invalid-shake.json

フックと、その依存関係をプロジェクトに追加します。

import { useInvalidShake } from "@/hooks/use-invalid-shake"
const ref = React.useRef<HTMLSelectElement>(null)
useInvalidShake(ref)

<form>
  <select
    ref={ref}
    required
    className="data-shake:motion-safe:animate-button-shake"
  >
    …
  </select>
  <button type="submit">Continue</button>
</form>

このフックが設定するのは data-shake 属性だけです。動きはテーマの animate-button-shake によるもので、data-shake:motion-safe:animate-button-shake で付けます。HextaUI の Input、Textarea、Native select、Input group にはそのクラスがすでに含まれていて、フックも呼んでいます。独自のコントロールでは直接使ってください。

揺れは「なぜ送信できなかったのか」という1つの問いに答えます。そのためこのフックは、送信を試みた直後にだけ揺れ、フォームに入力している最中には揺れません。

イベント説明
Submit attempt送信ボタンのクリック、フォームの入力欄での Enter、またはフォームの submit イベント。
Invalid within 600msコントロールが invalid を発火するか、aria-invalid="true"、data-invalid、:user-invalid を持つ場合です。これにはネイティブのバリデーション、Base UI のフィールド、送信直後に設定されるサーバーエラーが含まれます。
Shakedata-shake は400ms設定されます。これらのシグナルがいくつ届いても、1回の試みにつき1回だけ揺れます。
  • InputGroup の内側では、内側のコントロールだけでなく、グループ全体が揺れます。
  • 視差効果の軽減が有効な場合は、何も設定されません。揺れはメッセージではなく合図なので、どちらの場合も、揺れに加えて表示されるエラーメッセージを組み合わせてください。
  • このフックでは、コントロールが <form> に属している必要があります。属していない場合は何もしません。
  • コントロールごとに enabled 引数でオフにするか、HextaUI の入力欄では shake={false} を指定します。
  • 属性を再設定するとアニメーションが再開するため、1回目がまだ実行中でも、2回目の失敗では再び揺れます。
  • ネイティブのバリデーションは、送信時に最初の無効なコントロールにフォーカスします。揺れはその上に動きを加えるだけで、フォーカスを動かすことはありません。
プロパティ型デフォルト
ref監視するフォームコントロール。
RefObject<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement | null>–
enabled揺れるかどうか。
booleantrue
属性説明
data-shake送信の試みが失敗した後の400msの間、コントロールまたはその InputGroup に付きます。

Input、Textarea、NativeSelect、InputGroup。