Tailwind를 사용하여 재사용 가능한 React 구성 요소 빌드
게시 됨: 2022-03-10이 게시물에서는 다른 구성 요소에 대한 멋진 인터페이스를 노출하면서 내부적으로 Tailwind를 활용하는 재사용 가능한 React 구성 요소를 구축할 수 있는 여러 가지 방법을 살펴보겠습니다. 이렇게 하면 긴 클래스 이름 목록에서 읽기 및 유지 관리가 더 쉬운 시맨틱 소품으로 이동하여 코드를 개선할 수 있습니다.
이 게시물을 잘 이해하려면 React로 작업해야 합니다.
Tailwind는 개발자가 맞춤형 디자인을 구축하는 데 도움이 되는 저수준 유틸리티 클래스를 제공하는 매우 인기 있는 CSS 프레임워크입니다. 두 가지 문제를 정말 잘 해결했기 때문에 지난 몇 년 동안 인기가 높아졌습니다.
- Tailwind를 사용하면 일치하는 CSS 선택기를 찾기 위해 스타일시트를 뒤지지 않고 HTML을 반복적으로 쉽게 변경할 수 있습니다.
- Tailwind에는 정상적인 규칙과 기본값이 있습니다. 이것은 사람들이 CSS를 처음부터 작성하지 않고도 쉽게 시작할 수 있도록 합니다.
포괄적인 문서를 추가하면 Tailwind가 인기 있는 이유가 됩니다.
이러한 방법은 다음과 같은 코드를 변환하는 데 도움이 됩니다.
<button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"> Enable </button>
다음과 같은 코드를 작성하려면:
<Button size="sm" textColor="white" bgColor="blue-500"> Enable </Button>
두 스니펫의 차이점은 첫 번째 스니펫에서는 표준 HTML 버튼 태그를 사용하고 두 번째 스니펫은 <Button>
구성요소를 사용했다는 것입니다. <Button>
구성 요소는 재사용성을 위해 구축되었으며 더 나은 의미 체계를 가지고 있기 때문에 더 읽기 쉽습니다. 긴 클래스 이름 목록 대신 속성을 사용하여 size
, textColor
및 bgColor
와 같은 다양한 속성을 설정합니다.
시작하자.
방법 1: Classnames 모듈로 클래스 제어하기
Tailwind를 React 애플리케이션에 적용하는 간단한 방법은 클래스 이름을 수용하고 프로그래밍 방식으로 전환하는 것입니다.
classnames npm 모듈을 사용하면 React에서 클래스를 쉽게 토글할 수 있습니다. 이것을 사용하는 방법을 보여주기 위해 React 애플리케이션에 <Button>
구성 요소가 있는 사용 사례를 살펴보겠습니다.
// This could be hard to read. <button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">Enable</button> // This is more conventional React. <Button size="sm" textColor="white" bgColor="blue-500">Enable</Button>
이 <Button>
컴포넌트를 사용하는 사람들이 size
, textColor
및 bgColor
와 같은 React props를 사용할 수 있도록 Tailwind 클래스를 분리하는 방법을 살펴보겠습니다.
-
bgColor
및textColor
와 같은 소품을 클래스 이름 문자열 템플릿에 직접 전달합니다. - 객체를 사용하여 클래스 이름을 프로그래밍 방식으로 전환합니다(
size
소품에서 수행한 것처럼).
아래 예제 코드에서 두 가지 접근 방식을 모두 살펴보겠습니다.
// Button.jsx import classnames from 'classnames'; function Button ({size, bgColor, textColor, children}) { return ( <button className={classnames("bg-${bgColor} text-${textColor} font-bold py-2 px-4 rounded", { "text-xs": size === 'sm' "text-xl": size === 'lg', })}> {children} </button> ) }; export default Button;
위의 코드에서 다음 소품을 사용하는 Button
구성 요소를 정의합니다.
-
size
버튼의 크기를 정의하고 Tailwind 클래스text-xs
또는text-xl
을 적용합니다. -
bgColor
버튼의 배경색을 정의하고 Tailwindbg-*
클래스를 적용합니다. -
textColor
버튼의 텍스트 색상을 정의하고 Tailwindtext-* classes
를 적용합니다. -
children
모든 하위 구성 요소는 여기를 통해 전달됩니다. 일반적으로<Button>
안에 텍스트가 포함됩니다.
Button.jsx
를 정의하여 이제 클래스 이름 대신 React props를 가져오고 사용할 수 있습니다. 이렇게 하면 코드를 더 쉽게 읽고 재사용할 수 있습니다.
import Button from './Button'; <Button size="sm" textColor="white" bgColor="blue-500">Enable</Button>
대화형 구성 요소에 클래스 이름 사용
버튼은 매우 간단한 사용 사례입니다. 더 복잡한 것은 어떻습니까? 글쎄, 이것을 더 발전시켜 대화형 구성 요소를 만들 수 있습니다.
예를 들어 Tailwind를 사용하여 만든 드롭다운을 살펴보겠습니다.
Tailwind 및 클래스 이름 전환을 사용하여 구축된 대화형 드롭다운입니다.
이 예에서는 Tailwind CSS 클래스 이름을 사용하여 HTML 구성 요소를 생성하지만 다음과 같은 React 구성 요소를 노출합니다.
<Dropdown options={\["Edit", "Duplicate", "Archive", "Move", "Delete"\]} onOptionSelect={(option) => { console.log("Selected Option", option)} } />
위의 코드를 보면 Tailwind 클래스가 없음을 알 수 있습니다. 그것들은 모두 <Dropdown/>
의 구현 코드 안에 숨겨져 있습니다. 이 Dropdown
구성 요소의 사용자는 option
을 클릭할 때 options
목록과 클릭 핸들러 onOptionSelect
를 제공하기만 하면 됩니다.
Tailwind를 사용하여 이 구성 요소를 구축하는 방법을 살펴보겠습니다.
관련 없는 코드 중 일부를 제거하면 여기에 논리의 핵심이 있습니다. 전체 예제를 보려면 이 Codepen을 볼 수 있습니다.
import classNames from 'classnames'; function Dropdown({ options, onOptionSelect }) { // Keep track of whether the dropdown is open or not. const [isActive, setActive] = useState(false); const buttonClasses = `inline-flex justify-center w-full rounded-md border border-gray-300 px-4 py-2 bg-white text-sm leading-5 font-medium text-gray-700 hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-blue-500 active:text-gray-200 transition ease-in-out duration-150`; return ( // Toggle the dropdown if the button is clicked <button onClick={() => setActive(!isActive)} className={buttonClasses}> Options </button> // Use the classnames module to toggle the Tailwind .block and .hidden classes <div class={classNames("origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg", { block: isActive, hidden: !isActive })}> // List items are rendered here. {options.map((option) => <div key={option} onClick={(e) => onOptionSelect(option)}>{option}</div>)} </div> ) } export default Dropdown;
드롭다운은 .hidden
및 .block
클래스를 사용하여 선택적으로 표시하거나 숨김으로써 대화형으로 만들어집니다. <button>
을 누를 때마다 isActive
상태를 토글하는 onClick
핸들러를 시작합니다. 버튼이 활성화되면( isActive === true
) block
클래스를 설정합니다. 그렇지 않으면 hidden
클래스를 설정합니다. 이는 표시 동작을 토글하기 위한 Tailwind 클래스입니다.

요약하면 classnames 모듈은 Tailwind의 클래스 이름을 프로그래밍 방식으로 제어하는 간단하고 효과적인 방법입니다. 로직을 React props로 쉽게 분리할 수 있어 구성 요소를 더 쉽게 재사용할 수 있습니다. 단순하고 대화형 구성 요소에 대해 작동합니다.
방법 2: 상수를 사용하여 디자인 시스템 정의하기
Tailwind와 React를 함께 사용하는 또 다른 방법은 상수를 사용하고 props를 특정 상수에 매핑하는 것입니다. 이것은 설계 시스템을 구축하는 데 효과적입니다. 예를 들어 설명하겠습니다.
디자인 시스템을 나열하는 theme.js
파일로 시작하십시오.
// theme.js (you can call it whatever you want) export const ButtonType = { primary: "bg-blue-500 hover:bg-blue-700 text-white font-bold rounded", secondary: "bg-blue-500 hover:bg-blue-700 text-white font-bold rounded", basic: "bg-white hover:bg-gray-700 text-gray-700 font-bold rounded", delete: "bg-red-300 hover:bg-red-500 text-white font-bold rounded" }; export const ButtonSize = { sm: "py-2 px-4 text-xs", lg: "py-3 px-6 text-lg" }
이 경우 두 가지 상수 집합이 있습니다.
-
ButtonType
은 앱에서 버튼의 스타일을 지정하는 방법을 정의합니다. -
ButtonSizes
는 앱의 버튼 크기를 정의합니다.
이제 <Button>
구성 요소를 작성해 보겠습니다.
import {ButtonType, ButtonSize} from './theme'; function Button({size, type, children}) { // This can be improved. I'm keeping it simple here by joining two strings. const classNames = ButtonType[type] + " " + ButtonSize[size]; return ( <button className={classNames}>{children}</button> ) } export default Button;
ButtonType
및 ButtonSize
상수를 사용하여 클래스 이름 목록을 만듭니다. 이것은 <Button>
의 인터페이스를 훨씬 더 멋지게 만듭니다. 클래스 이름 문자열에 모든 것을 넣는 대신 size
및 type
소품을 사용할 수 있습니다.
// Cleaner and well defined props. <Button size="xs" type="primary">Enable</Button>
이전 접근 방식과 비교:
// Exposing class names <button className="py-2 px-4 text-xs bg-blue-500 hover:bg-blue-700 text-white font-bold rounded">Enable</button>
애플리케이션에서 버튼이 어떻게 보이는지 재정의해야 하는 경우 theme.js
파일을 편집하기만 하면 앱의 모든 버튼이 자동으로 업데이트됩니다. 이것은 다양한 구성 요소에서 클래스 이름을 검색하는 것보다 쉬울 수 있습니다.
방법 3: @apply
로 유틸리티 구성
React 구성 요소의 가독성을 향상시키는 세 번째 방법은 CSS와 PostCSS에서 사용 가능한 @apply
패턴을 사용하여 반복되는 클래스를 추출하는 것입니다. 이 패턴은 스타일시트와 후처리기를 사용합니다.
예제를 통해 이것이 어떻게 작동하는지 보여줍시다. 기본 및 보조 버튼이 있는 버튼 그룹이 있다고 가정합니다.

<button className="py-2 px-4 mr-4 text-xs bg-blue-500 hover:bg-blue-700 text-white font-bold rounded">Update Now</button> <button className="py-2 px-4 text-xs mr-4 hover:bg-gray-100 text-gray-700 border-gray-300 border font-bold rounded">Later</button>
@apply
패턴을 사용하여 이 HTML을 다음과 같이 작성할 수 있습니다.
<button className="btn btn-primary btn-xs">Update Now</button> <button className="btn btn-secondary btn-xs">Later</button>
그런 다음 React에 채택되어 다음과 같이 될 수 있습니다.
import classnames from "classnames"; function Button ({size, type, children}) { const bSize = "btn-" + size; const bType = "btn-" + type; return ( <button className={classnames("btn", bSize, bType)}>{children}</button> ) } Button.propTypes = { size: PropTypes.oneOf(['xs, xl']), type: PropTypes.oneOf(['primary', 'secondary']) }; // Using the Button component. <Button type="primary" size="xs">Update Now</Button> <Button type="secondary" size="xs">Later</Button>
.btn
, .btn-primary
등과 같은 BEM 스타일 클래스 이름을 만드는 방법은 다음과 같습니다. button.css
파일을 생성하여 시작합니다.
/\* button.css \*/ @tailwind base; @tailwind components; .btn { @apply py-2 px-4 mr-4 font-bold rounded; } .btn-primary { @apply bg-blue-500 hover:bg-blue-700 text-white; } .btn-secondary { @apply hover:bg-gray-700 text-gray-700 border-gray-300 border; } .btn-xs { @apply text-xs; } .btn-xl { @apply text-xl; } @tailwind utilities;
위의 코드는 실제 CSS가 아니지만 PostCSS에 의해 컴파일됩니다. JavaScript 프로젝트에 PostCSS 및 Tailwind를 설정하는 방법을 보여주는 GitHub 리포지토리가 있습니다.
여기에서 설정하는 방법을 보여주는 짧은 비디오도 있습니다.
@apply
사용의 단점
Tailwind 유틸리티 클래스를 더 높은 수준의 CSS 클래스로 추출하는 개념은 이치에 맞는 것처럼 보이지만 알고 있어야 하는 몇 가지 단점이 있습니다. 다른 예를 들어 이를 강조해 보겠습니다.
먼저 이러한 클래스 이름을 추출하여 일부 정보를 잃게 됩니다. 예를 들어 .btn-primary
는 이미 .btn
이 적용된 구성 요소에 추가되어야 합니다. 또한 .btn-primary
와 .btn-secondary
는 함께 적용할 수 없습니다. 이 정보는 클래스만 보면 알 수 없습니다.
이 구성 요소가 더 복잡한 경우 클래스 간의 부모-자식 관계도 이해해야 합니다. 어떤 면에서 이것은 Tailwind가 해결하도록 설계된 문제이며 @apply
를 사용하여 다른 방식으로 문제를 다시 가져오고 있습니다.
다음은 Tailwind의 제작자인 Adam Wathan이 @apply
사용의 장단점에 대해 설명하는 동영상입니다.
요약
이 기사에서는 Tailwind를 React 애플리케이션에 통합하여 재사용 가능한 구성 요소를 구축하는 세 가지 방법을 살펴보았습니다. 이러한 메서드는 props
를 사용하여 더 깔끔한 인터페이스를 가진 React 구성 요소를 빌드하는 데 도움이 됩니다.
- 클래스 이름 모듈을 사용하여 프로그래밍 방식으로 클래스를 토글합니다.
- 구성 요소 상태당 클래스 목록을 정의하는 상수 파일을 정의합니다.
-
@apply
를 사용하여 더 높은 수준의 CSS 클래스를 추출합니다.
질문이 있으면 Twitter @tilomitra로 메시지를 보내주십시오.
SmashingMag에 대한 권장 읽기 :
- React 프로젝트에서 Tailwind CSS 설정하기
- React로 정렬 가능한 테이블 만들기
- Firefox의 새롭고 실험적인 CSS DevTools 가이드
- 자신만의 확장 및 축소 콘텐츠 패널 만들기