ツクログネット

【React】ON/OFFスイッチを作る

eye catch

iPhoneの設定アプリ内で使われているようなON/OFFスイッチをReactで作ります。

コンポーネントを作成する

はじめに、ToggleSwitchButtonという名前のコンポーネントを作ります。

ToggleSwitchButton.js
import React from 'react'

const ToggleSwitchButton = ({ className, handleChange }) => (
	<div className={className}>
		<input id="btn-mode" type="checkbox" onChange={handleChange} ref={ref} />
		<label htmlFor="btn-mode">
    </label>
	</div>
)

export default ToggleSwitchButton

ToggleSwitchButtonコンポーネントについては次の通りです。

ON/OFFの仕組み

ビューはlabel要素とinput(type="checkbox")要素で構成されています。

ON/OFFスイッチは、input(type="checkbox")要素を利用して作り、チェックボックスにチェックを入れる=スイッチON、チェックを外す=スイッチOFFということにします。

また、CSSの:checkedを使用すれば、チェックが入ったときのスタイルを指定できるため、JS無しでON/OFFスイッチに動きを持たせられそうです。

と言いたいところですが、そうはいきません。なぜなら、CSSでinput(type="checkbox")要素の見た目をガラッと変えることができないからです。input(type="checkbox")要素に指定できるCSSプロパティはheightやwidth、marginといったものだけなのです。

これではON/OFFスイッチの見た目に装飾することはできません。

そこでlabel要素の出番です。

label要素の存在意義

label要素はなんのために必要なのか。

それは、input(type="checkbox")要素との関係性にあります。

label要素のfor属性とinput(type="checkbox")要素のid属性の値を等しくすることで、label要素とinput(type="checkbox")要素が紐づきます。

これにより、label要素のクリック=input(type="checkbox")要素のチェックということになるのです。

label要素であれば、どんなCSSプロパティでも指定できるため、ON/OFFスイッチの見た目に装飾が可能です。

CSSでON/OFFスイッチの見た目を表現する

それでは、CSSでlabel要素をON/OFFスイッチの見た目に装飾します。

今回はCSSファイルに書かずに、コンポーネントにスタイルを持たせる方法をとります。そのほうがコンポーネント単位でスタイルを管理できるためです。

コンポーネントにスタイルを持たせるには、styled-componentsを使います。

styled-componentsを使うには、まず下記のコマンドでstyled-componentsをインストールします。

yarn add styled-components

そして、styled-componentsのimport後、以下のようにしてStyledToggleSwitchButtonコンポーネントを作成します。

尚、StyledToggleSwitchButtonコンポーネントは、ToggleSwitchButtonコンポーネントの上に定義します。

ToggleSwitchButton.js
import React from 'react'
import styled from 'styled-components'

const StyledToggleSwitchButton = styled.div`
	& input {
		display: none;
		&:checked + label {
			background-color: #003366;
			&::before {
				left: 2em;
			}
		}
	}

	& label {
		background-color: #ff9933;
		border-radius: 2em;
		border: 2px solid var(--text-color);
		display: flex;
		align-items: center;
		justify-content: space-around;
		height: 2em;
		position: relative;
		transition: .5s;
		width: 3.75em;

		&::before {
			background: #fff;
			border-radius: 100%;
			content: '';
			display: inline-block;
			height: 1.5em;
			position: absolute;
			left: 0.25em;
			transition: .5s ease-out;
			width: 1.5em;
			z-index: 2;
		}
	}
`

const ToggleSwitchButton = ({ className, handleChange }) => (
// 省略
)

export default ToggleSwitchButton

StyledToggleSwitchButtonコンポーネントについてですが、styled.div`...`とすることで、div要素とその子要素に対するスタイルを``内に定義しています。

スタイルについてですが、ON/OFFスイッチ全体の見た目はlabel要素で作りますが、ON/OFFスイッチの動く部分(●の部分)の見た目はlabel要素内のbefore要素で作ります。

更に、:checkedでlabel要素がクリックされたとき(チェックが入ったとき)に、スイッチの背景色をダーク仕様に変更し、また、●の部分がONの方向へ移動するようにします。

尚、label要素があればinput要素は表示する必要がないため、display: none;で非表示にします。

& input {
		display: none;
		&:checked + label {
			background-color: #003366;
			&::before {
				left: 2em;
			}
		}
	}

スタイルについては以上です。

最後に、ToggleSwitchButtonコンポーネントをStyledToggleSwitchButtonコンポーネントで囲います。こうすることで、ToggleSwitchButtonコンポーネントがStyledToggleSwitchButtonコンポーネントの``内で定義したスタイルを持つようになります。

ToggleSwitchButton.js
// 省略

const ToggleSwitchButton = ({ className, handleChange }) => (
	<StyledToggleSwitchButton className={className}>
		<input id="btn-mode" type="checkbox" onChange={handleChange} ref={ref} />
		<label htmlFor="btn-mode">

		</label>
	</StyledToggleSwitchButton>
)

export default ToggleSwitchButton

ON/OFFスイッチを表示する

完成したToggleSwitchButtonコンポーネントをApp.jsにimport後、Appコンポーネントのビューに追加してページにON/OFFスイッチを表示させます。

Appコンポーネントを以下のようにします。(※importの際のパスはご自身のディレクトリ構成に合わせてください。)

App.js
import React from 'react';
import ToggleSwitchButton from './components/ToggleSwitchButton'

const App = () => {
	const [isToggle, setIsToggle] = useState(false)

	const handleChange = useCallback(() => {
		if(isToggle) {
			setIsToggle(false)
		}else{
			setIsToggle(true)
		}
	}, [isToggle])

	useEffect(() => {
		if(isToggle) {
			alert('switch on!')
		}else{
			alert('switch off!')
		}
	}, [isToggle])

	return (
		<div>
			<ToggleSwitchButton className="toggle-switch-button" handleChange={handleChange} />
		</div>
	);
};

export default App

上記では、propsとしてToggleSwitchButtonコンポーネントに独自に定義したhandleChange関数を渡しています。

これにより、スイッチをON/OFFにするとhandleChange関数が実行されてスイッチがONであれば「switch on!」のアラートが、OFFであれば「switch off!」のアラートが表示されます。

Demo

この記事をシェアする

関連する記事