Security News
RubyGems.org Adds New Maintainer Role
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.
@headlessui/vue
Advanced tools
@headlessui/vue is a set of completely unstyled, fully accessible UI components for Vue.js, designed to integrate seamlessly with Tailwind CSS. It provides the building blocks for creating custom, accessible UI components without imposing any design decisions.
Dialog (Modal)
The Dialog component is used to create accessible modals. The example demonstrates how to open and close a dialog with a button click.
<template>
<div>
<button @click="isOpen = true">Open Dialog</button>
<Dialog v-if="isOpen" @close="isOpen = false">
<DialogOverlay />
<DialogTitle>Payment successful</DialogTitle>
<DialogDescription>
Your payment has been successfully submitted. We’ve sent you an email with all of the details of your order.
</DialogDescription>
<button @click="isOpen = false">Got it, thanks!</button>
</Dialog>
</div>
</template>
<script>
import { ref } from 'vue';
import { Dialog, DialogOverlay, DialogTitle, DialogDescription } from '@headlessui/vue';
export default {
components: { Dialog, DialogOverlay, DialogTitle, DialogDescription },
setup() {
const isOpen = ref(false);
return { isOpen };
}
};
</script>
Listbox (Select)
The Listbox component is used to create accessible select dropdowns. The example shows how to bind a list of options to a Listbox and handle selection.
<template>
<div>
<Listbox v-model="selectedPerson">
<ListboxButton>{{ selectedPerson.name }}</ListboxButton>
<ListboxOptions>
<ListboxOption v-for="person in people" :key="person.id" :value="person">
{{ person.name }}
</ListboxOption>
</ListboxOptions>
</Listbox>
</div>
</template>
<script>
import { ref } from 'vue';
import { Listbox, ListboxButton, ListboxOptions, ListboxOption } from '@headlessui/vue';
export default {
components: { Listbox, ListboxButton, ListboxOptions, ListboxOption },
setup() {
const people = ref([
{ id: 1, name: 'Wade Cooper' },
{ id: 2, name: 'Arlene Mccoy' },
{ id: 3, name: 'Devon Webb' }
]);
const selectedPerson = ref(people.value[0]);
return { people, selectedPerson };
}
};
</script>
Popover
The Popover component is used to create accessible popover elements. The example demonstrates a simple popover with a button that reveals a panel of links.
<template>
<div>
<Popover>
<PopoverButton>Solutions</PopoverButton>
<PopoverPanel>
<a href="#">Insights</a>
<a href="#">Automations</a>
<a href="#">Reports</a>
</PopoverPanel>
</Popover>
</div>
</template>
<script>
import { Popover, PopoverButton, PopoverPanel } from '@headlessui/vue';
export default {
components: { Popover, PopoverButton, PopoverPanel }
};
</script>
vue-accessible-modal is a Vue.js component for creating accessible modals. It focuses on providing a simple API for creating modals that are compliant with accessibility standards. Compared to @headlessui/vue, it is more specialized and does not offer a wide range of UI components.
vue-select is a Vue.js component for creating customizable select dropdowns. It offers a rich set of features like tagging, filtering, and async options. While it provides more advanced features for select elements, it does not offer the breadth of components available in @headlessui/vue.
vue-popperjs is a Vue.js wrapper for Popper.js, a library used to manage poppers in web applications. It provides a flexible way to create tooltips, popovers, and dropdowns. Compared to @headlessui/vue, it is more focused on positioning and does not include other UI components.
A set of completely unstyled, fully accessible UI components for Vue 3, designed to integrate beautifully with Tailwind CSS.
Please note that this library only supports Vue 3.
# npm
npm install @headlessui/vue
# Yarn
yarn add @headlessui/vue
This project is still in early development. New components will be added regularly over the coming months.
This project is still in early development, but the plan is to build out all of the primitives we need to provide interactive Vue examples of all of the components included in Tailwind UI, the commercial component directory that helps us fund the development of our open-source work like Tailwind CSS.
This includes things like:
...and more in the future.
We'll be continuing to develop new components on an on-going basis, with a goal of reaching a pretty fleshed out v1.0 by the end of the year.
View complete demo on CodeSandbox
The Menu
component and related child components are used to quickly build custom dropdown components that are fully accessible out of the box, including correct ARIA attribute management and robust keyboard navigation support.
Menu Buttons are built using the Menu
, MenuButton
, MenuItems
, and MenuItem
components.
The MenuButton
will automatically open/close the MenuItems
when clicked, and when the menu is open, the list of items receives focus and is automatically navigable via the keyboard.
<template>
<Menu>
<MenuButton> More </MenuButton>
<MenuItems>
<MenuItem v-slot="{ active }">
<a :class="{ 'bg-blue-500': active }" href="/account-settings"> Account settings </a>
</MenuItem>
<MenuItem v-slot="{ active }">
<a :class="{ 'bg-blue-500': active }" href="/account-settings"> Documentation </a>
</MenuItem>
<MenuItem v-slot="{ active }" disabled>
<span :class="{ 'bg-blue-500': active }"> Invite a friend (coming soon!) </span>
</MenuItem>
</MenuItems>
</Menu>
</template>
<script>
import { Menu, MenuButton, MenuItems, MenuItem } from '@headlessui/vue'
export default {
components: {
Menu,
MenuButton,
MenuItems,
MenuItem,
},
}
</script>
This is a headless component so there are no styles included by default. Instead, the components expose useful information via scoped slots that you can use to apply the styles you'd like to apply yourself.
To style the active MenuItem
you can read the active
slot prop, which tells you whether or not that menu item is the item that is currently focused via the mouse or keyboard.
You can use this state to conditionally apply whatever active/focus styles you like, for instance a blue background like is typical in most operating systems.
<template>
<Menu>
<MenuButton> More </MenuButton>
<MenuItems>
<!-- Use the `active` state to conditionally style the active item. -->
<MenuItem v-slot="{ active }">
<a href="/settings" :class="active ? 'bg-blue-500 text-white' : 'bg-white text-black'">
Settings
</a>
</MenuItem>
<!-- ... -->
</MenuItems>
</Menu>
</template>
By default, your MenuItems
instance will be shown/hidden automatically based on the internal open
state tracked within the Menu
component itself.
<template>
<Menu>
<MenuButton> More </MenuButton>
<!-- By default, this will automatically show/hide when the MenuButton is pressed. -->
<MenuItems>
<MenuItem v-slot="{ active }">
<a :class="{ 'bg-blue-500': active }" href="/account-settings"> Account settings </a>
</MenuItem>
<!-- ... -->
</MenuItems>
</Menu>
</template>
If you'd rather handle this yourself (perhaps because you need to add an extra wrapper element for one reason or another), you can add a static
prop to the MenuItems
instance to tell it to always render, and inspect the open
slot prop provided by the Menu
to control which element is shown/hidden yourself.
<template>
<Menu v-slot="{ open }">
<MenuButton> More </MenuButton>
<div v-show="open">
<!-- Using `static`, `MenuItems` is always rendered and ignores the `open` state. -->
<MenuItems static>
<MenuItem v-slot="{ active }">
<a :class="{ 'bg-blue-500': active }" href="/account-settings"> Account settings </a>
</MenuItem>
<!-- ... -->
</MenuItems>
</div>
</Menu>
</template>
Use the disabled
prop to disable a MenuItem
. This will make it unselectable via keyboard navigation, and it will be skipped when pressing the up/down arrows.
<template>
<Menu>
<MenuButton> More </MenuButton>
<MenuItems>
<MenuItem disabled>
<span class="opacity-75">Invite a friend (coming soon!)</span>
</MenuItem>
<!-- ... -->
</MenuItems>
</Menu>
</template>
To animate the opening/closing of the menu panel, use Vue's built-in transition
component. All you need to do is wrap your MenuItems
instance in a <transition>
element and the transition will be applied automatically.
<template>
<Menu>
<MenuButton> More </MenuButton>
<transition
enter-active-class="transition duration-100 ease-out"
enter-from-class="transform scale-95 opacity-0"
enter-to-class="transform scale-100 opacity-100"
leave-active-class="transition duration-75 ease-out"
leave-from-class="transform scale-100 opacity-100"
leave-to-class="transform scale-95 opacity-0"
>
<MenuItems>
<MenuItem v-slot="{ active }">
<a :class="{ 'bg-blue-500': active }" href="/account-settings"> Account settings </a>
</MenuItem>
<!-- ... -->
</MenuItems>
</transition>
</Menu>
</template>
The Menu
component is not limited to rendering only its related subcomponents. You can render anything you like within a menu, which gives you complete control over exactly what you are building.
For example, if you'd like to add a little header section to the menu with some extra information in it, just render an extra div
with your content in it.
<template>
<Menu>
<MenuButton> More </MenuButton>
<MenuItems>
<div class="px-4 py-3">
<p class="text-sm leading-5">Signed in as</p>
<p class="text-sm font-medium leading-5 text-gray-900 truncate">tom@example.com</p>
</div>
<MenuItem v-slot="{ active }">
<a :class="{ 'bg-blue-500': active }" href="/account-settings"> Account settings </a>
</MenuItem>
<!-- ... -->
</MenuItems>
</Menu>
</template>
Note that only MenuItem
instances will be navigable via the keyboard.
By default, the Menu
and its subcomponents each render a default element that is sensible for that component.
For example, MenuButton
renders a button
by default, and MenuItems
renders a div
. Menu
and MenuItem
interestingly do not render an extra element, and instead render their children directly by default.
This is easy to change using the as
prop, which exists on every component.
<template>
<!-- Render a `div` instead of no wrapper element -->
<Menu as="div">
<MenuButton> More </MenuButton>
<!-- Render a `ul` instead of a `div` -->
<MenuItems as="ul">
<!-- Render an `li` instead of no wrapper element -->
<MenuItem as="li" v-slot="{ active }">
<a href="/account-settings" :class="{ 'bg-blue-500': active }"> Account settings </a>
</MenuItem>
<!-- ... -->
</MenuItems>
</Menu>
</template>
To tell an element to render its children directly with no wrapper element, use as="template"
.
<template>
<Menu>
<!-- Render no wrapper, instead pass in a button manually -->
<MenuButton as="template">
<button>More</button>
</MenuButton>
<MenuItems>
<MenuItem v-slot="{ active }">
<a href="/account-settings" :class="{ 'bg-blue-500': active }"> Account settings </a>
</MenuItem>
<!-- ... -->
</MenuItems>
</Menu>
</template>
<Menu v-slot="{ open }">
<MenuButton>More options</MenuButton>
<MenuItems>
<MenuItem><!-- ... --></MenuItem>
<!-- ... -->
</MenuItems>
</Menu>
Prop | Type | Default | Description |
---|---|---|---|
as | String | Component | template (no wrapper element) | The element or component the Menu should render as. |
Prop | Type | Description |
---|---|---|
open | Boolean | Whether or not the menu is open. |
<MenuButton v-slot="{ open }">
<span>More options</span>
<ChevronRightIcon :class="open ? 'transform rotate-90' : ''" />
</MenuButton>
Prop | Type | Default | Description |
---|---|---|---|
as | String | Component | button | The element or component the MenuButton should render as. |
Prop | Type | Description |
---|---|---|
open | Boolean | Whether or not the menu is open. |
<MenuItems>
<MenuItem><!-- ... --></MenuItem>
<!-- ... -->
</MenuItem>
Prop | Type | Default | Description |
---|---|---|---|
as | String | Component | div | The element or component the MenuItems should render as. |
static | Boolean | false | Whether the element should ignore the internally managed open/closed state. |
Prop | Type | Description |
---|---|---|
open | Boolean | Whether or not the menu is open. |
<MenuItem v-slot="{ active }">
<a href="/settings" :class="active ? 'bg-blue-500 text-white' : 'bg-white text-black'">
Settings
</a>
</MenuItem>
Prop | Type | Default | Description |
---|---|---|---|
as | String | Component | template (no wrapper element) | The element or component the MenuItem should render as. |
disabled | Boolean | false | Whether or not the item should be disabled for keyboard navigation and ARIA purposes. |
Prop | Type | Description |
---|---|---|
active | Boolean | Whether or not the item is the active/focused item in the list. |
disabled | Boolean | Whether or not the item is the disabled for keyboard navigation and ARIA purposes. |
FAQs
A set of completely unstyled, fully accessible UI components for Vue 3, designed to integrate beautifully with Tailwind CSS.
The npm package @headlessui/vue receives a total of 59,035 weekly downloads. As such, @headlessui/vue popularity was classified as popular.
We found that @headlessui/vue demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 4 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.
Security News
Node.js will be enforcing stricter semver-major PR policies a month before major releases to enhance stability and ensure reliable release candidates.
Security News
Research
Socket's threat research team has detected five malicious npm packages targeting Roblox developers, deploying malware to steal credentials and personal data.