w3school에 들어가면 'How to create a toggle switch'라는 글이 있다. react로 만들기 전 이 글을 참고하며 기능구현을 고민했다.
HTML : w3school에는 rounded 버전과 rectangular 버전이 있었다. 라운드를 참고해 만들기 시작했다.
<!-- Rectangular switch -->
<label class="switch">
<input type="checkbox">
<span class="slider"></span>
</label>
<!-- Rounded switch -->
<label class="switch">
<input type="checkbox">
<span class="slider round"></span>
</label>
toggleSwitch.jsx파일을 만들어 랜더 부분을 우선 작성했다. css는 postcss를 이용했다. 예제와 달리 내가 만드는 토글은 클릭하는 순간 배경색이 왼쪽부터 오른쪽 끝까지 채워지는 애니메이션 효과가 있어야 했다. 토글 버튼과 별개로 배경처리를 해줘야 해서 span class를 2개 만들었다.
<div className={styles.toggleSwitch}>
<input
type="checkbox"
className={styles.checkbox}
id="toggleSwitch"
/>
</div>
<label className={styles.label} htmlFor="toggleSwitch">
<span className={styles.toggleInner} />
<span className={styles.switch} />
</label>
기존의 input checkbox는 dipslay를 없애주고 기능만 남겨놓아야 한다. label클래스로 버튼 모양을 잡고, toggleInner와 switch를 배치해준다.
가장 신경써야 하는 부분은 toggleInner인데, css 가상요소 선택자인 :before, :after를 사용해줘야한다. 이 때 주의해야할 것은 content인데, 내용이 없다고 지워버리면 요소가 아예 사라진다.
toggleInner의 전체 넓이는 토글의 200%로 주고 before에는 핑크로, after에은 회색을 적용한다. checkbox가 checked가 되면 toggleInner가 왼쪽으로 100% 가도록하게 만들어줘야 해서 초기값을 margin-left: -100%으로 세팅해준다.
.toggleInner {
display: block;
width: 200%;
margin-left: -100%;
}
.toggleInner:before,
.toggleInner:after {
float: left;
width: 50%;
height: 36px;
padding: 0;
box-sizing: border-box;
content: "";
}
.toggleInner:before {
background-color: pink;
}
.toggleInner:after {
background-color: #bbb;
}
배경색과 함께 버튼도 움직여야 한다. 스위치 버튼을 만들어준다.
.switch {
display: block;
width: 24px;
margin: 5px;
background: #fff;
position: absolute;
top: 0;
bottom: 0;
right: 40px;
border: 0 solid #bbb;
border-radius: 50%;
}
.checkbox:checked + .label .toggleInner {
margin-left: 0;
}
.checkbox:checked + .label .switch {
right: 0px;
}
/* toggleinner와 switch에 적용 */
/* switch의 transition property는 all을 적용한다 */
transition: margin-left 0.3s ease-in;
컴포넌트 state 관리를 통해 text가 변화할 수 있도록 했다.
const onChangeText = e => {
console.log(e.target.checked);
if (e.target.checked === false) {
setOnOff("OFF");
} else if (e.target.checked === true) {
setOnOff("ON");
}
};