LoginSignup
25
7

More than 1 year has passed since last update.

React Datepickerを日本っぽいカレンダーにカスタムする

Last updated at Posted at 2022-04-30

概要

before

スクリーンショット 2022-04-29 21.42.02.png

  • 曜日表示が英語
  • 入力欄が月/日/年の順番になっている
  • カレンダーのヘッダーの月表記が英語
  • カレンダーのヘッダーの表記が月→年の順番になっている

after

スクリーンショット 2022-04-29 23.51.31.png

  • 曜日表記を日本語化
  • 入力欄を年/月/日の順番に修正
  • カレンダーのヘッダーを数字+「年」 数字+「月」と日本式の表記・順番に修正
  • ついでに月曜始まり化

手順

準備

Next.jsとTypeScriptを以下のように導入する。

ターミナル
$ yarn create next-app

$ cd [app名]

$ yarn add -D typescript @types/react @types/node

$ touch tsconfig.json

# ここで_app.jsとindex.jsの拡張子を.tsxに書き換える

$ yarn dev

Chakra UIとReact Date Pickerも同様に導入する。

ターミナル
$ yarn add @chakra-ui/react @emotion/react@^11 @emotion/styled@^11 framer-motion@^6

$ yarn add react-datepicker

_app.tsxをChakra UIを利用するために下記のように書き換える。

_app.tsx
import "../styles/globals.css";

import { ChakraProvider } from "@chakra-ui/react";

function MyApp({ Component, pageProps }) {
  return (
    <ChakraProvider>
      <Component {...pageProps} />
    </ChakraProvider>
  );
}

export default MyApp;

index.tsxにReact Date Pickerを導入するため下記のように書き換える。

index.tsx
import { Box } from "@chakra-ui/react";
import { useState } from "react";
import DatePicker from "react-datepicker";

import "react-datepicker/dist/react-datepicker.css";

export default function Home() {
  const [startDate, setStartDate] = useState(new Date());

  return (
    <Box w="250px" mt="30px" ml="30px">
      <DatePicker
        selected={startDate}
        onChange={(date) => setStartDate(date)}
      />
    </Box>
  );
}

この状態でyarn devすると最初に紹介したようなプレーンな英語版のカレンダーが表示される。
スクリーンショット 2022-04-29 21.42.02.png

日本っぽいカレンダーに改造する

day.jsを導入しておく。

ターミナル
$ yarn add dayjs

componentsディレクトリを作成しその配下にDatePicker.tsxを下記のように作成する。

DatePicker.tsx
import ja from 'date-fns/locale/ja'
import dayjs from 'dayjs'
import React from 'react'
import ReactDatePicker, { ReactDatePickerProps, registerLocale } from 'react-datepicker'

registerLocale('ja', ja)

export const DatePicker = (props: ReactDatePickerProps) => {
  return (
    <div className="light-theme-original">
      <ReactDatePicker
        locale={ja}
        renderCustomHeader={({ date, decreaseMonth, increaseMonth }) => (
          <div className="datepicker__header">
            <button className="datepicker__button" onClick={decreaseMonth}>
              {'<'}
            </button>
            <div className="datepicker__header-date">
              <div className="datepicker__header-date__year">{dayjs(date).year()}</div>
              <div className="datepicker__header-date__month">{dayjs(date).month() + 1}</div>
            </div>
            <button className="datepicker__button" onClick={increaseMonth}>
              {'>'}
            </button>
          </div>
        )}
        {...props}
      />
    </div>
  )
}

上記のコード中、locale={ja}の設定で曜日表記を日本語にしている。
このままだとヘッダーの年と月の並びが4月 2022という感じで月→年の順番になるので、 renderCustomHeaderで年と月の記述を設定することで順番を変更している。

index.tsxも下記のように書き換える。

index.tsx
import React, { useState } from "react";
import { DatePicker } from "../components/DatePicker";
import { Box } from "@chakra-ui/react";

export default function Home() {
  const [startDate, setStartDate] = useState(new Date());

  return (
    <Box w="250px" mt="30px" ml="30px">
      <DatePicker
        selected={startDate}
        onChange={(date) => setStartDate(date)}
        dateFormat="yyyy/MM/dd"
        calendarStartDay={1}
      />
    </Box>
  );
}

dateFormat="yyyy/MM/dd"で入力欄の並びを「年月日」にしている。
また、calendarStartDay={1}で月曜始まりのカレンダーに変更している。

https://gist.github.com/igoro00/99e9d244677ccafbf39667c24b5b35ed を参考に、
stylesディレクトリにdate-picker.cssを準備して下記のように記述する。
(※参考元のdate-picker.cssにheader関連のスタイルを追加している)

date-picker.css
.light-theme {
  --light-gray: var(--chakra-colors-gray-200);
  --gray: var(--chakra-colors-gray-300);
  --blue700: var(--chakra-colors-blue-600);
  --blue600: var(--chakra-colors-blue-500);
  --blue500: var(--chakra-colors-gray-400);
  --blue400: var(--chakra-colors-gray-300);
  --blue300: var(--chakra-colors-gray-200);
  --blue200: var(--chakra-colors-gray-200);
  --blue100: var(--chakra-colors-gray-100);
  --monthBackground: var(--chakra-colors-white);
  --text: var(--chakra-colors-black);
  --negative-text: var(--chakra-colors-white);
}
.dark-theme {
  --light-gray: var(--chakra-colors-gray-600);
  --gray: var(--chakra-colors-gray-500);
  --blue700: var(--chakra-colors-blue-600);
  --blue600: var(--chakra-colors-blue-300);
  --blue500: var(--chakra-colors-gray-500);
  --blue400: var(--chakra-colors-gray-600);
  --blue300: var(--chakra-colors-gray-700);
  --blue200: var(--chakra-colors-gray-600);
  --blue100: var(--chakra-colors-gray-800);
  --monthBackground: var(--chakra-colors-gray-700);
  --text: var(--chakra-colors-gray-200);
  --negative-text: var(--chakra-colors-black);
}

/* if you dont want to use chakra's theme use this class in the wrapping div. These are the exact original values */
.light-theme-original {
  --light-gray: #cccccc;
  --gray: #b3b3b3;
  --blue700: #2a69ac;
  --blue600: #3182ce;
  --blue500: #a0aec0;
  --blue400: #cbd5e0;
  --blue300: #e2e8f0;
  --blue200: #edf2f7;
  --blue100: #f7fafc;
}
.react-datepicker {
  font-family: unset;
  font-size: 0.9rem;
  border-color: var(--light-gray);
}

.react-datepicker-wrapper,
.react-datepicker__input-container {
  display: block;
}

.react-datepicker__input-container {
  font-size: 1rem;
  padding-left: 1rem;
  padding-right: 1rem;
  height: 2.5rem;
  border-radius: 0.25rem;
  border: 1px solid;
  border-color: var(--light-gray);
}
.react-datapicker__input-text {
  background-color: transparent;
}

.react-datepicker__input-container:hover {
  border-color: var(--gray);
}
.react-datepicker__input-container:focus-within {
  z-index: 1;
  border-color: var(--blue600);
  box-shadow: 0 0 0 1px var(--blue600);
}

.react-datepicker__input-container > input {
  width: 100%;
  height: 100%;
  outline: 0;
}

.react-datepicker__navigation--next--with-time:not(.react-datepicker__navigation--next--with-today-button) {
  right: 90px;
}

.react-datepicker__navigation--previous,
.react-datepicker__navigation--next {
  height: 8px;
}

.react-datepicker__navigation--previous {
  border-right-color: var(--blue400);
}

.react-datepicker__navigation--previous:hover {
  border-right-color: var(--blue500);
}

.react-datepicker__navigation--next {
  border-left-color: var(--blue400);
}

.react-datepicker__navigation--next:hover {
  border-left-color: var(--blue500);
}

.react-datepicker__header {
  background-color: var(--blue100);
}

.react-datepicker__header,
.react-datepicker__time-container {
  border-color: var(--blue300);
}

.react-datepicker__current-month,
.react-datepicker-time__header,
.react-datepicker-year-header {
  font-size: inherit;
  font-weight: 600;
  color: var(--text);
}

.react-datepicker__month {
  background-color: var(--monthBackground);
  margin: 0;
  padding: 0.4rem;
}

.react-datepicker__time-container
  .react-datepicker__time
  .react-datepicker__time-box
  ul.react-datepicker__time-list
  li.react-datepicker__time-list-item {
  margin: 0 1px 0 0;
  height: auto;
  padding: 7px 10px;
}

.react-datepicker__time-container
  .react-datepicker__time
  .react-datepicker__time-box
  ul.react-datepicker__time-list
  li.react-datepicker__time-list-item:hover {
  background: var(--blue200);
}

.react-datepicker__day {
  color: var(--text);
}

.react-datepicker__day:hover {
  background: var(--blue200);
}

.react-datepicker__day-name {
  color: var(--text);
}

.react-datepicker__day--selected,
.react-datepicker__day--in-selecting-range,
.react-datepicker__day--in-range,
.react-datepicker__month-text--selected,
.react-datepicker__month-text--in-selecting-range,
.react-datepicker__month-text--in-range,
.react-datepicker__time-container
  .react-datepicker__time
  .react-datepicker__time-box
  ul.react-datepicker__time-list
  li.react-datepicker__time-list-item--selected {
  background: var(--blue600);
  font-weight: normal;
  color: var(--negative-text);
}

.react-datepicker__time-container
  .react-datepicker__time
  .react-datepicker__time-box
  ul.react-datepicker__time-list
  li.react-datepicker__time-list-item--selected:hover {
  background: var(--blue700);
}

.react-datepicker__close-icon::after {
  background-color: unset;
  border-radius: unset;
  font-size: 1.5rem;
  font-weight: bold;
  color: var(--light-gray);
  height: 20px;
  width: 20px;
}

.react-datepicker__close-icon::after:hover {
  color: var(--gray);
}

.datepicker__header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 15px;
  font-weight: bold;
}

.datepicker__header-date {
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 1.5em;
}

.datepicker__header-date__year {
  margin-right: 7px;
}

.datepicker__button {
  font-size: 1.25em;
  color: #757575;
}

_app.tsxに下記を追記してスタイルを適用する。

_app.tsx
import "../styles/date-picker.css";
import "react-datepicker/dist/react-datepicker.css";

見慣れた&使い慣れた日本式カレンダーの完成!

スクリーンショット 2022-04-29 23.51.31.png

参考

25
7
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
25
7