요런 걸 만들어보자.
색깔은 라디오 버튼으로 만들었다.
색깔을 선택하면 스마일 이모지가 선택한 색깔로 이동한다.
여기서 사용해 볼 수 있다.
https://blog.doitreviews.com/custom-radio-button/
이전에 만들어 둔 git repo를 clone하자.
https://github.com/angelxtry/react-typescript-without-cra
git clone 후 yarn으로 package를 설치한다.
styled-components를 사용할 것이다. 설치하다.
yarn add styled-components
yarn add -D @types/styled-components
불필요한 파일들을 삭제하자.
폴더 및 파일을 다음과 같다.
tree -I node_modules
.
├── README.md
├── package.json
├── src
│ ├── App.tsx
│ ├── images
│ ├── index.html
│ ├── index.tsx
│ └── types
│ └── custom.d.ts
├── tsconfig.json
├── webpack.config.js
└── yarn.lock
CustomRadioButton.tsx 파일을 생성한다.
import React from 'react';
const Colors = [
{ name: 'RED', hex: '#ffb598' },
{ name: 'ORANGE', hex: '#ffdcaa' },
{ name: 'PURPLE', hex: '#d7beff' },
{ name: 'CYAN', hex: '#c7f5ed' },
{ name: 'BLUE', hex: '#c2dbff' },
];
export function CustonRadioButton() {
return (
<>
{Colors.map((color) => (
<div key={color.name}>
<input
id={color.name}
type="radio"
name="color-selector"
value={color.name}
/>
<label htmlFor={color.name}>{color.name}</label>
</div>
))}
</>
);
}
기본적인 라디오 버튼을 생성했다.
App.tsx
import React from 'react';
import { CustonRadioButton } from './CustonRadioButton';
export default function App() {
return (
<div>
<h1>색깔을 선택하세요!</h1>
<CustonRadioButton />
</div>
);
}
화면에 출력했다.
styled-components로 스타일을 추가한다.
import React from 'react';
import styled from 'styled-components';
import selectIconUrl from './images/ic-selected.svg';
const Colors = [
{ name: 'RED', hex: '#ffb598' },
{ name: 'ORANGE', hex: '#ffdcaa' },
{ name: 'PURPLE', hex: '#d7beff' },
{ name: 'CYAN', hex: '#c7f5ed' },
{ name: 'BLUE', hex: '#c2dbff' },
];
const ColorSelectorContainer = styled.div`
display: flex;
justify-content: space-between;
width: 500px;
margin-top: 8px;
padding: 10px;
border: 1px solid salmon;
`;
const Label = styled.label`
display: inline-block;
width: 40px;
height: 40px;
border-radius: 20px;
background-color: ${(props) => props.color};
`;
const RadioButton = styled.input`
display: none;
&:checked + ${Label} {
background: center url(${selectIconUrl}) no-repeat ${(props) => props.color};
}
`;
export function CustonRadioButton() {
return (
<>
<ColorSelectorContainer>
{Colors.map((color) => (
<div key={color.name}>
<RadioButton
id={color.name}
type="radio"
name="color-selector"
value={color.name}
color={color.hex}
/>
<Label htmlFor={color.name} color={color.hex} />
</div>
))}
</ColorSelectorContainer>
</>
);
}
label과 input에 color.hex를 전달하여 backgroundColor를 설정한다.
input에 display: none;
을 적용하면 라디오 버튼이 사라지고 label만 남는다.
몇 가지 기능을 더 추가해보자.
라디오 버튼이 생성될 때 하나의 값이 선택되어 있도록 초기값을 설정하도록 한다.
그리고 특정 색을 선택하면 해당 색의 이름이 출력되고 border가 해당 색으로 변경되도록 설정한다.
CustomRadioButton.tsx
import React, { useState } from 'react';
import styled from 'styled-components';
import selectIconUrl from './images/ic-selected.svg';
type Color = {
name: string;
hex: string;
};
const Colors: Color[] = [
{ name: 'RED', hex: '#ffb598' },
{ name: 'ORANGE', hex: '#ffdcaa' },
{ name: 'PURPLE', hex: '#d7beff' },
{ name: 'CYAN', hex: '#c7f5ed' },
{ name: 'BLUE', hex: '#c2dbff' },
];
const ColorSelectorContainer = styled.div`
display: flex;
justify-content: space-between;
width: 500px;
margin-top: 8px;
padding: 10px;
border: 5px solid ${(props) => props.color};
`;
const Label = styled.label`
display: inline-block;
width: 40px;
height: 40px;
border-radius: 20px;
background-color: ${(props) => props.color};
`;
const RadioButton = styled.input`
display: none;
&:checked + ${Label} {
background: center url(${selectIconUrl}) no-repeat ${(props) => props.color};
}
`;
const SelectResult = styled.div`
font-family: 'apple sd gothic neo';
`;
interface CustonRadioButtonProps {
initialColor: Color;
}
export function CustonRadioButton({ initialColor }: CustonRadioButtonProps) {
const [selectedColor, setSelectedColor] = useState<Color>(initialColor);
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { value } = e.target;
const selected = Colors.filter((color) => color.name === value);
if (selected) {
setSelectedColor(selected[0]);
}
};
return (
<>
<ColorSelectorContainer color={selectedColor.hex}>
{Colors.map((color) => (
<div key={color.name}>
<RadioButton
id={color.name}
type="radio"
name="color-selector"
value={color.name}
checked={color.name === selectedColor.name}
color={color.hex}
onChange={onChange}
/>
{/* {color.name} */}
<Label htmlFor={color.name} color={color.hex} />
</div>
))}
</ColorSelectorContainer>
<SelectResult>{selectedColor.name}</SelectResult>
</>
);
}
App.tsx
import React from 'react';
import { CustonRadioButton } from './CustonRadioButton';
export default function App() {
const initialColor = { name: 'RED', hex: '#ffb598' };
return (
<div>
<h1>색깔을 선택하세요!</h1>
<CustonRadioButton initialColor={initialColor} />
</div>
);
}
앞으로는 라디오 버튼 만들 때 어떻게 만들었더라… 하지 않겠지?