11
4

More than 1 year has passed since last update.

Next.js × ChakraUIでフォーカスを調整する

Posted at

Next.jsでChakraUIを使っての開発時にフォーカスとそのスタイルで意外と気にすることが多かったので紹介します。

Next.jsでページ間リンクにフォーカスがつかない

Next.jsでサイト内遷移のリンクを作成するとき、next/linkを使います。

普通に使うとこんな感じですが、

.jsx
import Link from 'next/link'
export const Hoge = () => {
  return (
    <Link href={'/about'}>
      <a>About Us</a>
    </Link>
  )
}

リンクにChakraUIのスタイルを使いたい場合や、ChakraUIの書式でスタイルをつけたい場合は、aタグのかわりにChakraUIのリンクコンポーネントを使います。(他のタグに置き換えない場合はaタグで出力されます)

.jsx
import Link from 'next/link'
import { Link as ChakraLink } from '@chakra-ui/react'

export const Hoge = () => {
  return (
    <Link href={'/about'} passHref>
      <ChakraLink>About Us</ChakraLink>
    </Link >
  )
}

このとき気をつけたいのが、passHrefです。Next.jsのLinkコンポーネントの直下の子要素がコンポーネントである場合、passHrefを付けないとaタグにhrefが出力されません。

.html
<!-- passHrefがあるとき -->
<a href="/about">About Us</a>
<!-- passHrefがないとき(遷移は普通にできる) -->
<a>About Us</a>

https://nextjs.org/docs/api-reference/next/link#if-the-child-is-a-custom-component-that-wraps-an-a-tag
If the child is a custom component that wraps an <a> tag

そしてhrefがないとフォーカスもつきません。
最初これに気づかずローカル環境だからhrefがないのかな…などと考えていましたが、passHrefです。
Next.jsが提供しているESLintプラグインにこれをチェックするものも含まれています。適宜使いたいです。

overflow hiddenするとフォーカスが欠ける

ChakraUIのUIコンポーネントのフォーカスは、特にカスタマイズしていない場合外側にbox-shadowでスタイルがつきます。
このスタイルはboxShadow='outline'で任意の場所に使うことも可能です。

.jsx
<Box boxShadow={'outline'} p={6} rounded={'md'} bg={'white'}>
  Outline
</Box>

ChakraUIを使ってカスタムコンポーネントに対してスタイルを書く中で、LinkやButtonの親要素にoverflow: hiddenを指定するとフォーカスのスタイルが要素の外側につくため、フォーカスが一部表示されなくなることがあります。
boxShadow='outline'のようなフォーカススタイルでなんとか表示できるようにしたい場合は、boxShadowinsetをつけると内側にShadowをつけられます。

.jsx
<Link
  href={'/piyo'}
  _focus={{
    boxShadow: '0 0 0 3px rgba(66, 153, 225, 0.6) inset',
    outline: 'none'
  }}
>
  piyo
</Link>

フォーカススタイルの見た目が違うコンポーネントがある

ChakraUIのコンポーネントを素直に使っている場合は問題ないのですが、Boxをbuttonにして使ったりするとBoxにはフォーカス時のスタイルがないので、フォーカスするとブラウザデフォルトのoutlineについたスタイルになります。気にする場合は_focusのスタイルを設定します。

.jsx
<Box
  as={'button'}
  _focus={{
    boxShadow: 'outline'
  }}
>
  hoge
</Box>

input要素にフォーカスがつかない

ChakraUIあまり関係ないです。
type="file"のinputにスタイルをつけるとき、labelタグで囲うとラベルをクリックして動作するinputになるのですが、フォーカスがつきません。labelにはフォーカスしないためです。
buttonなどのフォーカスする要素で見た目を作成し、その操作にinputが連動するような実装にするとフォーカスするUIにできます。

.jsx
export const FileInput = () => {
  const inputRef = ref as React.MutableRefObject<HTMLInputElement>
  const clickHandler = () => {
    inputRef.current.click()
  }
  return (
    <>
      // フォーカスが表示されない
      <FormLabel cursor={'pointer'}>
        <Input
          type={'file'}
          opacity={0}
          visibility={'hidden'}
          onChange={onChange}
        />
      </FormLabel>

      // フォーカス表示される
      <Box as={'button'} type={'button'} onClick={clickHandler}>ファイル添付</Box>
      <Input
        type={'file'}
        opacity={0}
        visibility={'hidden'}
        ref={ref}
        onChange={onChange}
      />
    </>
  )
}

フォーカスをキーボード操作時のみにしたい

フォーカスをキーボード操作時のみにしたい場合は、focus-visibleが使えます。

ChakraUIのstyle propsにも_focusVisibleがあるので、これを使えば指定できます。

.jsx
<Tab
  _focus={{
    boxShadow: 'none',
  }}
  _focusVisible={{
    boxShadow: 'outline',
  }}
>
  hoge
</Tab>

まとめ

ChakraUIは元々フォーカスに限らずアクセシビリティに考慮されて作られています。そのためコンポーネントを素直に使えばわりあい快適なUIが実装ができるのですが、自分でカスタムコンポーネントを作り始めるとそうはいかなくなってきます。なるべくうまくやりたいものです。

11
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
4