Headless UI v1.0

Date

지난 가을, 우리는 Headless UI를 발표했습니다. 이 라이브러리는 완전히 스타일이 적용되지 않은 접근성 있는 UI 컴포넌트로, Tailwind CSS와 완벽하게 어울리도록 설계되었습니다.

오늘 우리는 Headless UI v1.0을 출시하게 되어 매우 기쁩니다. 이번 버전은 React와 Vue 모두를 위한 컴포넌트 수를 두 배 이상 늘렸습니다.

Headless UI

새로운 기능

React 라이브러리에 4개의 새로운 컴포넌트를 추가했고, Vue에는 5개의 새로운 컴포넌트를 추가했습니다.

Dialog (모달)

Headless UI는 이제 강력한 다이얼로그 구현을 제공합니다. 이를 통해 전통적인 모달 다이얼로그, 모바일 슬라이드 아웃 메뉴, 또는 전체 페이지의 포커스를 잡아야 하는 기타 UI를 구축할 수 있습니다.

import { useState } from 'react'
import { Dialog } from '@headlessui/react'

function MyDialog() {
  let [isOpen, setIsOpen] = useState(true)

  return (
    <Dialog open={isOpen} onClose={setIsOpen}>
      <Dialog.Overlay />

      <Dialog.Title>계정 비활성화</Dialog.Title>
      <Dialog.Description>
        이 작업은 계정을 영구적으로 비활성화합니다.
      </Dialog.Description>

      <p>
        정말로 계정을 비활성화하시겠습니까? 모든 데이터가 영구적으로 삭제됩니다. 이 작업은 취소할 수 없습니다.
      </p>

      <button onClick={() => setIsOpen(false)}>비활성화</button>
      <button onClick={() => setIsOpen(false)}>취소</button>
    </Dialog>
  )
}

Disclosure

새로운 Disclosure 컴포넌트를 추가했습니다. 이 컴포넌트는 접근성 있게 인라인 콘텐츠를 보여주거나 숨기는 기능을 쉽게 구현할 수 있게 해줍니다. 이는 접을 수 있는 FAQ 질문, “더 보기” 인터페이스, 또는 페이지의 나머지 콘텐츠를 밀어내며 열리는 햄버거 메뉴와 같은 기능에 유용합니다.

<template>
  <Disclosure>
    <DisclosureButton> 팀 가격 정책을 이용할 수 있나요? </DisclosureButton>
    <DisclosurePanel>
      네! 팀 전체와 공유할 수 있는 라이선스를 구매할 수 있습니다.
    </DisclosurePanel>
  </Disclosure>
</template>

<script>
  import {
    Disclosure,
    DisclosureButton,
    DisclosurePanel,
  } from '@headlessui/vue'

  export default {
    components: { Disclosure, DisclosureButton, DisclosurePanel },
  }
</script>

라디오 그룹

이제 RadioGroup 컴포넌트를 사용해 완전히 커스텀한 라디오 버튼 UI를 만들 수 있습니다. 간단한 라디오 원형 대신 멋진 카드 같은 것을 사용하고 싶을 때 유용합니다.

import { useState } from 'react'
import { RadioGroup } from '@headlessui/react'

function MyRadioGroup() {
  let [plan, setPlan] = useState('startup')

  return (
    <RadioGroup value={plan} onChange={setPlan}>
      <RadioGroup.Label>Plan</RadioGroup.Label>
      <RadioGroup.Option value="startup">
        {({ checked }) => (
          <span className={checked ? 'bg-blue-200' : ''}>Startup</span>
        )}
      </RadioGroup.Option>
      <RadioGroup.Option value="business">
        {({ checked }) => (
          <span className={checked ? 'bg-blue-200' : ''}>Business</span>
        )}
      </RadioGroup.Option>
      <RadioGroup.Option value="enterprise">
        {({ checked }) => (
          <span className={checked ? 'bg-blue-200' : ''}>Enterprise</span>
        )}
      </RadioGroup.Option>
    </RadioGroup>
  )
}

Popover

새로운 Popover 컴포넌트를 사용하면 일반적인 Menu 컴포넌트와 달리 콘텐츠 제한 없이 커스텀 드롭다운 UI를 만들 수 있습니다. 마케팅 사이트의 플라이아웃 메뉴나 폼 필드가 포함된 드롭다운 등 다양한 용도로 활용할 수 있습니다.

<template>
  <Popover class="relative">
    <PopoverButton>Solutions</PopoverButton>

    <PopoverPanel class="absolute z-10">
      <div>
        <a href="/analytics">Analytics</a>
        <a href="/engagement">Engagement</a>
        <a href="/security">Security</a>
        <a href="/integrations">Integrations</a>
      </div>

      <img src="/solutions.jpg" alt="" />
    </PopoverPanel>
  </Popover>
</template>

<script>
  import { Popover, PopoverButton, PopoverPanel } from '@headlessui/vue'

  export default {
    components: { Popover, PopoverButton, PopoverPanel },
  }
</script>

TransitionRoot와 TransitionChild (Vue용)

Headless UI는 이미 React용 Transition 컴포넌트를 제공하고 있었지만, Vue 사용자에게는 Vue에 기본으로 포함된 <transition>을 사용할 것을 권장했습니다. 그러나 기본 transition에는 몇 가지 제한 사항이 있으며, 동시에 실행되어야 하는 중첩된 transition을 조율하려고 할 때 복잡해질 수 있습니다.

Headless UI v1.0에서는 React의 Transition 컴포넌트를 Vue로도 가져왔습니다. 이를 통해 모달 다이얼로그와 같은 요소를 더 쉽게 transition할 수 있습니다.

<template>
  <!-- `show` prop은 모든 중첩된 `Transition.Child` 컴포넌트를 제어합니다. -->
  <TransitionRoot :show="isOpen">
    <!-- 배경 오버레이 -->
    <TransitionChild
      enter="transition-opacity"
      ease-linear
      duration-300"
      enter-from="opacity-0"
      enter-to="opacity-100"
      leave="transition-opacity"
      ease-linear
      duration-300"
      leave-from="opacity-100"
      leave-to="opacity-0"
    >
      <!-- … -->
    </TransitionChild>

    <!-- 슬라이딩 사이드바 -->
    <TransitionChild
      enter="transition"
      ease-in-out
      duration-300
      transform"
      enter-from="-translate-x-full"
      enter-to="translate-x-0"
      leave="transition"
      ease-in-out
      duration-300
      transform"
      leave-from="translate-x-0"
      leave-to="-translate-x-full"
    >
      <!-- … -->
    </TransitionChild>
  </TransitionRoot>
</template>

<script>
  import { ref } from "vue";
  import { Transition, TransitionChild } from "@headlessui/vue";

  export default {
    components: { TransitionRoot: Transition, TransitionChild },

    setup() {
      const isShowing = ref(true);

      return {
        isShowing,
      };
    },
  };
</script>

직접 사용해 보기

새로워진 Headless UI 문서 웹사이트로 이동하여 프로젝트에 Headless UI를 추가하고 직접 사용해 보세요! MIT 라이선스로 제공되며 오픈소스이기 때문에, 코드를 살펴보거나 이슈를 보고하려면 GitHub 저장소를 방문하세요.

한번 사용해 보고 싶으신가요? Headless UI 웹사이트 방문하기 →