CSS 컴포넌트란?
원하는 HTML요소의 스타일링을 쉽게 할 수 있는 CSS 클래스를 'CSS 컴포넌트' 라고 하며 이를 제공하는 테일윈드CSS, daisyui 등을 CSS 프레임워크(혹은 CSS라이브러리)라고 한다.
색상 테마
웹 페이지에서 가장 많이 사용되는 색상을 주 색상(primary color)라고 한다. 웹 페이지 성격에 따라 주 색상이 다를 수 있으며 주색상과 함께 사용되는 보조 색상(secoundary-color)가 있다.
또한 필요에 따라 좀 더 다양한 색상을 사용할 수도 있다. 이런 테마 색상들을 '색상 테마 라고 한다.
Button 컴포넌트 구현하기
daisyui button CSS 컴포넌트의 형태를 react를 통해 간결하게 사용할 수 있음을 알 수 있다.
// 컴포넌트 미적용
<button className="btn btn-primary">button</button>
// 컴포넌트 적용
<Button className="btn-primary">button</button>
// className을 컴포넌트 내에 적용
<Button>button</Button>
우선 버튼 컴포넌트를 추가한다.
import type {FC, DetailedHTMLProps, ButtonHTMLAttributes, PropsWithChildren} from 'react'
export type ReactButtonProps = DetailedHTMLProps<
ButtonHTMLAttributes<HTMLButtonElement>,
HTMLButtonElement
>
export type ButtonProps = ReactButtonProps & {}
export const Button: FC<PropsWithChildren<ButtonProps>> = ({
...buttonProps
}) => {
return <button {...buttonProps} />
}
그후 버튼 테스트 인덱스를 구현한다.
import Basic from './Basic'
import Size from './Size'
import IconTest from './IconTest'
export default function ButtonTest() {
return (
<section className="mt-4">
<h2 className="text-5xl font-bold text-center">ButtonTest</h2>
<div className="mt-4">
<IconTest />
<Size />
<Basic />
</div>
</section>
)
}
다음으로는 베이직 버튼 버튼 테스트 코드를 추가한다.
import {Button} from '../../theme/daisyui'
export default function Basic() {
return (
<section className="mt-4">
<h2 className="font-bold text-3xl text-center">Basic</h2>
<div className="mt-4 flex justify-evenly">
<button className="btn btn-primary">daysiui button</button>
<Button className="btn btn-primary">Button</Button>
</div>
</section>
)
}
'btn' 부분 생략하기
daisyui의 button 컴포넌트는 btn 클래스를 항상 명시해 줘야 하므로 className에 btn클래스를 기본으로 설정해 불편함이 없도록 변경한다.
import type {FC, DetailedHTMLProps, ButtonHTMLAttributes, PropsWithChildren} from 'react'
export type ReactButtonProps = DetailedHTMLProps<
ButtonHTMLAttributes<HTMLButtonElement>,
HTMLButtonElement
>
export type ButtonProps = ReactButtonProps & {}
export const Button: FC<PropsWithChildren<ButtonProps>> = ({
className: _className,
...buttonProps
}) => {
const className = ['btn', _className].join(' ')
return <button {...buttonProps} className={className} />
}
버튼의 크기 설정하기
daisyui의 button 컴포넌트는 4가지 크기의 클래스를 제공하며 크기는 btn-lg, btn-md, btn-sm, btn-xs순이다.
import {Button} from '../../theme/daisyui'
export default function Size() {
return (
<section className="mt-4">
<h2 className="text-3xl font-bold text-center">Size</h2>
<div className="flex mt-4 justify-evenly">
<Button className="btn-lg btn-primary">Size lg</Button>
<Button className="btn-md btn-primary">Size md</Button>
<Button className="btn-sm btn-primary">Size sm</Button>
<Button className="btn-xs btn-primary">Size xs</Button>
</div>
</section>
)
}
Icon 컴포넌트 구현하기
<span>요소는 아이콘을 클릭했을 때 효과가 매끄럽게 표현되지 않는 경우가 있다. 그러므로 단점을 보완하기 위해 daisyui 버튼 CSS 컴포넌트로 <span>을 감싸면 해결할 수 있다. 다만 조금 코드 작성이 번거롭기 때문에 별도의 아이콘 컴포넌트를 추가한다.
import type {FC} from 'react'
import type {ButtonProps} from './Button'
import type {IconProps as CIconProps} from '../../components'
import {Button} from './Button'
import {Icon as CIcon} from '../../components'
export type IconProps = ButtonProps &
CIconProps & {
iconClassName?: string
}
export const Icon: FC<IconProps> = ({name, iconClassName, className, ...buttonProps}) => {
const btnClassName = ['btn-circle', className].join(' ')
return (
<Button {...buttonProps} className={btnClassName}>
<CIcon className={iconClassName} name={name} />
</Button>
)
}
추가된 컴포넌트를 통해 아이콘 버튼 확인 소스를 추가한다.
import {Icon} from '../../theme/daisyui'
export default function IconTest() {
const onclick = () => alert('Icon clicked')
return (
<section className="mt-4">
<h2 className="text-3xl font-bold text-center">IconTest</h2>
<div className="flex items-center justify-around mt-4">
<Icon className="btn-primary btn-lg" name="setttings" onClick={onclick} />
<Icon className="btn-secondary btn-md" name="done" onClick={onclick} />
<Icon className="btn-accent btn-sm" name="menu" onClick={onclick} />
<Icon className="btn-success btn-xs" name="file_upload" onClick={onclick} />
</div>
</section>
)
}
Input 컴포넌트 구현하기
<input>이 제공하는 속성값은 text, email, passsword 등 텍스트를 입력받는 형태로 쓰이며 daisyui input CSS 컴포넌트를 사용하려면 항상 input 클래스를 포함시켜야 하기 때문에 생략할 수 있게 Input 컴포넌트를 추가한다.
import type {FC, DetailedHTMLProps, InputHTMLAttributes} from 'react'
export type ReactInputProps = DetailedHTMLProps<
InputHTMLAttributes<HTMLInputElement>,
HTMLInputElement
>
export type inputProps = ReactInputProps & {}
export const Input: FC<inputProps> = ({className: _className, ...inputProps}) => {
const className = ['input', _className].join(' ')
return <input {...inputProps} className={className} />
}
컴포넌트 추가 후 컴포넌트를 사용할 소스를 추가한다. 하단의 소스르르 보는 것과 같이 Input 컴포넌트를 사용함에 따라 input 클래스를 생략한 것을 확인할 수 있다.
import {Input} from '../../theme/daisyui/Input'
export default function Basic() {
return (
<section className="mt-4">
<h2 className="text-3xl font-bold text-center">Basic</h2>
<div className="flex mt-4 justify-evenly">
<input className="input input-primary" />
<Input className="input-primary" />
</div>
</section>
)
}
색상 설정하기
input CSS 컴포넌트는 primary, secondary, accent, input, success, warning, error 등의 색상으로 경계를 표현할 수 있다.
해당 색상을 확인할 소스를 추가하자.
import {Input} from '../../theme/daisyui/Input'
export default function Color() {
return (
<section className="mt-4">
<h2 className="text-3xl font-bold text-center">Color</h2>
<div className="flex p-4 mt-4 justify-evenly">
<div>
<label className="label">input-primary</label>
<Input className="input-primary" />
</div>
<div>
<label className="label">input-secondary</label>
<Input className="input-secondary" />
</div>
<div>
<label className="label">input-accent</label>
<Input className="input-accent" />
</div>
<div>
<label className="label">input-info</label>
<Input className="input-info" />
</div>
<div>
<label className="label">input-success</label>
<Input className="input-success" />
</div>
<div>
<label className="label">input-warning</label>
<Input className="input-warning" />
</div>
<div>
<label className="label">input-error</label>
<Input className="input-error" />
</div>
</div>
</section>
)
}
테두리 설정하기
Input 컴포넌트에 테두리를 설정하기 위한 코드를 추가한다.
import {Input} from '../../theme/daisyui'
export default function Border() {
return (
<section className="mt-4">
<h2 className="text-3xl font-bold text-center">Border</h2>
<div className="flex mt-4 justify-evenly">
<div>
<label className="label">input-bordered</label>
<Input className="input-bordered" />
</div>
<div>
<label className="label">input-ghost</label>
<Input className="input-ghost" />
</div>
</div>
</section>
)
}
크기 설정하기
input CSS 컴포넌트는 lg, md, sm, xs 등으로 크기를 설정할 수 있다. 크기를 확인할 수 있는 코드를 추가하자.
import {Input} from '../../theme/daisyui/Input'
export default function Size() {
return (
<section className="mt-4">
<h2 className="text-3xl font-bold text-center">Size</h2>
<div className="flex p-4 mt-4 justify-evenly">
<div>
<label className="label">input-lg</label>
<Input className="input-primary input-lg" />
</div>
<div>
<label className="label">input-md</label>
<Input className="input-secondary input-md" />
</div>
<div>
<label className="label">input-sm</label>
<Input className="input-accent input-sm" />
</div>
<div>
<label className="label">input-xs</label>
<Input className="input-info input-xs" />
</div>
</div>
</section>
)
}
모달 컴포넌트 구현하기
팝업은 모달(modal) 팝업과 모덜리스(modeless) 팝업이 있다. 모달팝업은 새로운 창이 뜬 팝업을 의미하며 모달리스 팝업은 브라우저 안에 영역이 생겨 생성된 팝업을 의미한다.
daisyui는 modal, modal-box, modal-action 클래스로 모달 팝업을 제공하며 modal 클래스에 modal-open 클래스를 추가하면 대화 상자가 화면에 나타난다.
사용의 편의성을 위해 모달 컴포넌트 코드를 추가한다.
import type {FC} from 'react'
import type {ReactDivProps} from '../../components'
import {Div} from '../../components'
import {Icon} from './Icon'
export type ModalProps = ReactDivProps & {
open?: Boolean
}
export const Modal: FC<ModalProps> = ({open, className: _className, ...props}) => {
const className = ['modal', open ? 'modal-open' : '', _className].join(' ')
return <div {...props} className={className} />
}
export type ModalcontentProps = ReactDivProps & {
onCloseIconClicked?: () => void
closeIconClassName?: string
}
export const ModalContent: FC<ModalcontentProps> = ({
onCloseIconClicked,
closeIconClassName: _closeIconClassName,
className: _className,
children,
...props
}) => {
const showCloseIcon = onCloseIconClicked ? true : false
const className = ['modal-box', showCloseIcon && 'relative', _className].join(' ')
if (!showCloseIcon) {
return <div {...props} className={className} children={children} />
}
const closeIconClassName = _closeIconClassName ?? 'btn-primary btn-outline btn-sm'
return (
<div {...props} className={className}>
<Div className="absolute" right="0.5rem" top="0.5rem">
<Icon name="close" className={closeIconClassName} onClick={onCloseIconClicked} />
</Div>
{children}
</div>
)
}
export type ModalActionProps = ReactDivProps & {}
export const ModalAction: FC<ModalActionProps> = ({className: _className, ...props}) => {
const className = ['modal_action', _className].join(' ')
return <div {...props} className={className} />
}
해당 컴포넌트를 통해 화면에 보여줄 코드를 추가한다.
import {Title, Subtitle} from '../../components'
import {Modal, ModalContent, ModalAction, Button} from '../../theme/daisyui'
import * as D from '../../data'
export default function ModelTest() {
const open = true
const closeClicked = () => alert('closeClicked')
const acceptClicked = () => alert('acceptClicked')
return (
<section className="mt4">
<Title>ModalTest</Title>
<Modal open={open}>
<ModalContent onCloseIconClicked={closeClicked}>
<Subtitle>Modal</Subtitle>
<p className="mt-4 text-justify">{D.randomParagraphs()}</p>
<ModalAction>
<Button
className="w-24 normal-case btn-primary btn-sm"
onClick={acceptClicked}>
Accept
</Button>
<Button className="w-24 normal-case btn-sm" onClick={closeClicked}>
Close
</Button>
</ModalAction>
</ModalContent>
</Modal>
</section>
)
}
'FrontEnd > React' 카테고리의 다른 글
[React] useMemo와 useCallback 훅 이해하기 (0) | 2024.11.27 |
---|---|
[React] 처음 만나는 리액트 훅 (0) | 2024.11.26 |
[React] 플렉스 레이아웃 이해하기 (0) | 2024.11.24 |
[React] 테일윈드CSS 리액트 프로젝트 만들기 (1) | 2024.11.18 |
[React] 리액트 컴포넌트의 CSS 스타일링 (0) | 2024.11.18 |