かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

React × Chakra UI レスポンシブでサイズの変わるボタンを作りたい

モック作りに Chakra UI を採用してみました。

レスポンシブ時に大きさの変わる <Button> コンポーネントを作るのに少しハマってしまったのでメモ。

環境
@chakra-ui/icons: ^1.0.13
@chakra-ui/react: ^1.6.3

Chakra UI の Button コンポーネントでは size props に配列形式でレスポンシブ時のボタンサイズの設定ができない

width や margin や font-size の指定などは配列で指定することができました。

<Box fontSize={['xs', 'sm', 'md']}>
  Responsive font-size
</Box>

同じ様に Button コンポーネントの size を指定しようとすると型エラーが表示されました

<Button type="button" size={['sm', 'sm', 'md']}>
  My Button
</Button>
//  Type 'string[]' is not assignable to type '(string & {}) | "sm" | "md" | "lg" | "xs"'.
//  Type 'string[]' is not assignable to type '"xs"'.
//  (JSX attribute) ThemingProps<"Button">.size?: (string & {}) | "lg" | "md" | "sm" | "xs"

Button Props
size
Type: "sm" | "md" | "lg" | "xs"
Default: "md"
cf. Button - Chakra UI

Button コンポーネントsize porps の型は "sm" | "md" | "lg" | "xs" で配列のレスポンシブ指定はできないようです。

useBreakpointValue() を使って動的にレスポンシブ時の値を設定する

useBreakpointValue is a custom hook which returns the value for the current breakpoint from the provided responsive values object. This hook also responds to the window resizing and returning the appropriate value for the new window size.
cf. useBreakpointValue - Chakra UI

ブレイクポイントに合わせて予め渡しておいた値が返される hooks を使って動的に props を設定することができるようです。

import { useBreakpointValue } from '@chakra-ui/react';

const ResponsiveButton: VFC = () => {
  const buttonSize = useBreakpointValue(['sm', 'sm', 'md']);

  return (
    <Button type="button" size={buttonSize}>
      My Responsive Button
    </Button>
  );
};

buttonSize の値がブレイクポイントに合わせて変更され、Buttonコンポーネントのサイズをレスポンシブで変更できるようになりました!

note.

こちらで 2020 年に size props も配列・オブジェクト形式でのレスポンシブ指定ができるようにしようとする議論があり v2 で実装する ロードマップにも載ったようですが issue も PR (feat: allow responsive values for `variant` and `size` by dodas · Pull Request #3258 · chakra-ui/chakra-ui · GitHub) close されてしまっているので、当分はこの useBreakpointValue を使う方法でないとダメそうです。

感想

Chakra UI まだ新しいフレームワークですが、React で使いやすく特に機能的なものはサクット実装できて便利です。
一方、指定方法が違うのにドキュメントに書かれてなかったり、同じ sm でもコンポーネントや props によってサイズが異なったり、元の HTML に存在する attribute と同じ名前だけど指定方法が異なる props のオプションはあったりなどハマる部分が結構あり、困りごとが少し調べにくいな〜 (時間がかかる) という印象です。
フレームワークなので慣れの問題でもありますが、まだバージョンも低いので仕様も変わっていくのかなと思っています。


[参照]


この記事を書くために改めて調べていてスポンシブ時の指定方法、配列とオブジェクトで指定する方法があるのに気づきました。

import { createBreakpoints } from "@chakra-ui/theme-tools"
// This is the default breakpoint
const breakpoints = createBreakpoints({
  sm: "30em",
  md: "48em",
  lg: "62em",
  xl: "80em",
  "2xl": "96em",
})
// Internally, we transform to this
const breakpoints = ["0em", "30em", "48em", "62em", "80em", "96em"]

Examples

<>
  <Box
    height={{
      base: "100%", // 0-48em
      md: "50%", // 48em-80em,
      xl: "25%", // 80em+
    }}
    bg="teal.400"
    width={[
      "100%", // 0-30em
      "50%", // 30em-48em
      "25%", // 48em-62em
      "15%", // 62em+
    ]}
  />
</>

cf. Responsive Styles - Chakra UI

つまり

  • Chakra UI の Breakpoint 指定は全て min-width になっている
  • 配列の指定方法は ['0 < xm', 'xs < sm', 'sm < md', 'md < lg', 'lg < 2xl', ' 2xl =< ']
  • 0 < md までと sm =< のような指定は 配列で ["100%", "100%", "50%"] と書かなくても {base: '100%', md: '50%'} と書くことができる

ドキュメントはしっかり読もう… (今回の反省)

オタク今の推し作品をサムネイルに設定しがち…

これは違うチャクラ…