📻

ラジオボタンを押した際にスクロール位置がおかしくなる問題を解決する

2024/05/21に公開

問題

ラジオボタンが画面外に配置されている場合、そのラジオボタンのラベルをクリックするとブラウザがページのトップにジャンプすることがあります。
shadcn/ui の sheet コンポーネントにフォームを実装し、フォーム要素としてラジオボタンを実装しているときに起きました。shadcn/ui の RadioGroup で実装しているボタンをクリックすると、下記のように sheet 内のフォーム要素の表示位置がずれてしまいます。

該当のコード

<FormControl>
  <RadioGroup
    onValueChange={field.onChange}
    value={field.value}
    className="flex justify-center space-x-4 text-white"
  >
    <FormItem className="h-11 w-11 rounded-lg bg-gray-400 text-center font-semibold leading-10 peer-data-[state=checked]:bg-indigo-400 dark:bg-gray-500 [&:has([data-state=checked])]:bg-indigo-400">
      <FormControl>
        <RadioGroupItem
          value="cloudy"
          className="peer sr-only"
        />
      </FormControl>
      <FormLabel>白濁</FormLabel>
    </FormItem>
    <FormItem className="h-11 w-11 rounded-lg bg-gray-400 text-center font-semibold leading-10 peer-data-[state=checked]:bg-primary dark:bg-gray-500 [&:has([data-state=checked])]:bg-primary">
      <FormControl>
        <RadioGroupItem
          value="shed"
          className="peer sr-only"
        />
      </FormControl>
      <FormLabel>脱皮</FormLabel>
    </FormItem>
  </RadioGroup>
</FormControl>

解決策

以下のようにRadioGroupItemのクラスにfixedopacity-0を追加することで解決できます。

  <FormControl>
    <RadioGroupItem
      value="shed"
+     className="peer sr-only fixed opacity-0"
    />
  </FormControl>
  <FormLabel>脱皮</FormLabel>
  </FormItem>

  <FormControl>
    <RadioGroupItem
      value="shed"
-     className="peer sr-only"
    />
  </FormControl>
  <FormLabel>脱皮</FormLabel>
  </FormItem>

原因

ラジオボタンが非表示にされていても、その位置がブラウザによって参照されるため、ボタンを押したときにそのボタンにフォーカスがあたることが原因のようです。

https://stackoverflow.com/questions/24299567/radio-button-causes-browser-to-jump-to-the-top

position: fixed で、ラジオボタンが画面の特定の位置に「固定」されるため、ブラウザがその位置を参照しないようにすることができます。

参考

https://stackoverflow.com/questions/24299567/radio-button-causes-browser-to-jump-to-the-top

https://blog.bitsrc.io/customise-radio-buttons-without-compromising-accessibility-b03061b5ba93

Discussion