🔥 Oxide UI v0.1.0 — Dark mode only, copy-paste ready. Get started →
Skip to content

Plugins & Interactions

Oxide UI uses Headless UI v1 for Vue as its interaction layer — the same library made by Tailwind Labs. It handles all ARIA, keyboard navigation, and focus management so you don't have to.

For patterns that Headless UI doesn't cover (file upload, PIN input, etc.), lightweight custom Vue composables are provided instead.

Headless UI reference

Headless UI componentOxide UI pagePreline equivalent
DialogModalOverlay
MenuDropdownDropdown
DisclosureAccordionAccordion, Collapse
TabsTabsTabs
SwitchToggle
ListboxSelectAdvanced Select
ComboboxSelect → ComboboxComboBox
PopoverPopoverTooltip & Popover
RadioGroupRadio Group
TransitionUsed internally in all animated components

Why Headless UI over Preline plugins?

Preline uses a data-attribute (hs-dropdown, hs-overlay, etc.) JavaScript plugin that scans the DOM on load. This works fine for vanilla HTML but creates friction in Vue/Nuxt because:

  • It runs outside Vue's reactivity system
  • It requires window.HSStaticMethods.autoInit() after every Vue navigation
  • It conflicts with Vue's virtual DOM diffing
  • It doesn't integrate with Vue transitions or <Teleport>

Headless UI is renderless Vue components — they plug directly into Vue's reactivity, work with <Transition>, and generate correct ARIA automatically.

Custom implementations (no Headless UI equivalent)

These patterns require small custom implementations:

PatternApproach
StepperCustom ref + step array, see backlog
File upload (drag & drop)Native drag events + input[type=file]
PIN inputArray of single-char inputs + auto-focus logic
Strong password indicatorcomputed score from zxcvbn or custom regex
Toggle password visibilityref toggling type="text" / type="password"
Textarea autoheight@input event + el.style.height = el.scrollHeight + 'px'
CarouselCustom ref index + CSS translate or @vueuse/core useScroll
ScrollspyIntersectionObserver + active section tracking
Copy to clipboardnavigator.clipboard.writeText() + toast feedback
DatatablesTanStack Table for Vue

Installing Headless UI

bash
# npm
npm install @headlessui/vue

# pnpm
pnpm add @headlessui/vue

# yarn
yarn add @headlessui/vue

In Nuxt, no plugin registration is needed — import components directly:

vue
<script setup>
import { Dialog, DialogPanel, DialogTitle } from '@headlessui/vue'
</script>

Keyboard navigation (built-in)

All Headless UI components handle these automatically — no extra code required:

ComponentKeys
Menu (Dropdown) to navigate, Enter to select, Esc to close
Dialog (Modal)Esc to close, focus trapped inside
Disclosure (Accordion)Enter / Space to toggle
Tabs to switch panels
Combobox to navigate options, Enter to select, Esc to close
Switch (Toggle)Enter / Space to toggle
Listbox (Select) to navigate, Enter to select

Released under the MIT License.