无头 UI v1.0

日期

去年秋天,我们宣布了 无头 UI,这是一个完全无样式、完全可访问的 UI 组件库,旨在与 Tailwind CSS 完美搭配。

今天,我们非常高兴地发布 无头 UI v1.0,它将 React 和 Vue 的包含组件数量增加了一倍以上。

Headless UI

新增功能

我们在 React 库中添加了四个新组件,在 Vue 中添加了五个新组件。

对话框(模态)

无头 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>Deactivate account</Dialog.Title>
      <Dialog.Description>
        This will permanently deactivate your account
      </Dialog.Description>

      <p>
        Are you sure you want to deactivate your account? All of your data will
        be permanently removed. This action cannot be undone.
      </p>

      <button onClick={() => setIsOpen(false)}>Deactivate</button>
      <button onClick={() => setIsOpen(false)}>Cancel</button>
    </Dialog>
  )
}

公开

我们添加了一个新的 Disclosure 组件,它可以轻松地以可访问的方式显示/隐藏内联内容。这对于诸如可折叠的常见问题解答、"显示更多"界面,甚至打开并推开页面其余内容的汉堡菜单等内容很有用。

<template>
  <Disclosure>
    <DisclosureButton> Is team pricing available? </DisclosureButton>
    <DisclosurePanel>
      Yes! You can purchase a license that you can share with your entire team.
    </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 组件允许您构建自定义下拉 UI,这些 UI 没有像常规 Menu 组件那样的内容限制。非常适合营销网站上的弹出菜单、包含表单字段的下拉菜单等等。

<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>。但是,原生过渡有一些限制,当尝试协调应该并行运行的嵌套过渡时,事情可能会变得复杂。

Headless UI v1.0 也将我们的 React Transition 组件带到了 Vue,这使得过渡诸如模态对话框之类的元素变得更加容易。

<template>
  <!-- This `show` prop controls all nested `Transition.Child` components. -->
  <TransitionRoot :show="isOpen">
    <!-- Background overlay -->
    <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>

    <!-- Sliding sidebar -->
    <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 引入您的项目并体验它!它采用 MIT 许可证并开源,如果您想查看代码或需要报告问题,请 访问 GitHub 仓库

想试试吗? 访问 Headless UI 网站 →