@cakewalk/ngx-headlessui

headlessui for angular

Usage no npm install needed!

<script type="module">
  import cakewalkNgxHeadlessui from 'https://cdn.skypack.dev/@cakewalk/ngx-headlessui';
</script>

README

@cakewalk/ngx-headlessui

A set of completely unstyled, fully accessible UI components for Angular based on headlessui. Designed to integrate beautifully with Tailwind CSS.

New: Popover added

Installation

Tested with Angular 12.1.1 only.

# npm
npm install @cakewalk/ngx-headlessui

Components

This project is still in early development. So far, only Disclosure, Menu, Switch and Transition component is available. Also expect the API to change.

Disclosure (Expandable and Collapsible Panel)

Disclosure are built using Button and Panel components which are warpped in Disclosure

Markup

<hux-disclosure>
   <hux-disclosure-button>
      <button class="flex w-full text-left mb-4">
         <span class="flex-grow font-semibold">Header Text</span>
         <svg class="text-indigo-600 w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
         </svg>
      </button>
   </hux-disclosure-button>
   <hux-disclosure-panel>
      panel content...
   </hux-disclosure-panel>
</hux-disclosure>

Menu Button (Dropdown)

Basic example

Menu Buttons are built using the hlMenu, hlMenuButton, *hlMenuItems, and *hlMenuItem directives.

The menu button *hlMenuButton will automatically open/close the *hlMenuItems when clicked, and when the menu is open, the list of items receives focus and is automatically navigable via the keyboard.

<div hlMenu>
  <button hlMenuButton class="w-full">More</button>
  <div *hlMenuItems>
    <a *hlMenuItem="let item" [class.bg-blue-500]="item.active" href="./#account-settings">
      Account settings
    </a>
    <a *hlMenuItem="let item" [class.bg-blue-500]="item.active" href="./#documentation">
      Documentation
    </a>
    <span *hlMenuItem="let item; disabled: true">
      Invite a friend (coming soon!)
    </span>
    </div>
</div>

Styling the active item

This is a headless component so there are no styles included by default. Instead, the components expose useful information via let expressions that you can use to apply the styles you'd like to apply yourself.

To style the active hlMenuItem you can read the active state, 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.

<div hlMenu>
  <button hlMenuButton>More</button>
  <div *hlMenuItems>
    <!-- Use the `active` state to conditionally style the active item. -->
    <a *hlMenuItem="let item"
       [class]="item.active ? 'bg-blue-500 text-white' : 'bg-white text-black'" 
       href="#settings">
      Settings
    </a>
  </ul>
</div>

Switch (Checkbox)

The Switch component and related child components are used to quickly build custom switch/toggle components that are fully accessible out of the box, including correct ARIA attribute management and robust keyboard support.

Switches are built using the Switch component. Optionally you can also use the SwitchGroup and SwitchLabel components.

Markup:

<div SwitchGroup class="flex items-center space-x-4">
    <button Switch (change)="onChange($event)" class="w-11 focus:outline-none focus:shadow-outline relative inline-flex flex-shrink-0 h-6 transition-colors duration-200    ease-in-out border-2 border-transparent rounded-full cursor-pointer" [ngClass]="{'bg-indigo-600': switchValue, 'bg-gray-200': !switchValue}">
        <span class="inline-block w-5 h-5 transition duration-200 ease-in-out transform bg-white rounded-full" [ngClass]="{ 'translate-x-5': switchValue, 'translate-x-0': !switchValue }">
        </span>
    </button>
</div>

Using a custom label

By default the Switch will use the contents as the label for screenreaders. If you need more control, you can render a SwitchLabel outside of the Switch, as long as both the switch and label are within a parent SwitchGroup.

Clicking the label will toggle the switch state, like you'd expect from a native checkbox.

<div SwitchGroup class="flex items-center space-x-4">
  <span class="flex flex-col">
    <label SwitchLabel class="text-sm font-medium leading-5 text-gray-900">Enable notifications</label>
  </span>
  <button Switch (change)="onChange($event)" class="w-11 focus:outline-none focus:shadow-outline relative inline-flex flex-shrink-0 h-6 transition-colors duration-200 ease-in-out border-2 border-transparent rounded-full cursor-pointer" [ngClass]="{'bg-indigo-600': switchValue, 'bg-gray-200': !switchValue}">
    <span class="inline-block w-5 h-5 transition duration-200 ease-in-out transform bg-white rounded-full" [ngClass]="{ 'translate-x-5': switchValue, 'translate-x-0': !switchValue }"></span>
  </button>
</div>

Transition (Animation)

The Transition component lets you add enter/leave transitions to conditionally rendered elements, using CSS classes to control the actual transition styles in the different stages of the transition.

Markup:

<transition
    enter="transition-opacity duration-75"
    enterFrom="opacity-0"
    enterTo="opacity-100"
    leave="transition-opacity duration-150"
    leaveFrom="opacity-100"
    leaveTo="opacity-0">
    <span>I will fade in and out</span>
</transition>

By default, a Transition will enter and leave instantly, which is probably not what you're looking for if you're using this library.

To animate your enter/leave transitions, add classes that provide the styling for each phase of the transitions using these props:

  • enter Applied the entire time an element is entering. Usually you define your duration and what properties you want to transition here, for example transition-opacity duration-75.
  • enterFrom The starting point to enter from, for example opacity-0 if something should fade in.
  • enterTo The ending point to enter to, for example opacity-100 after fading in.
  • leave Applied the entire time an element is leaving. Usually you define your duration and what properties you want to transition here, for example transition-opacity duration-75.
  • leaveFrom The starting point to leave from, for example opacity-100 if something should fade out.
  • leaveTo The ending point to leave to, for example opacity-0 after fading out.

Props

Prop Type Description
show Boolean Whether the children should be shown or hidden.
enter String (Default: '') Classes to add to the transitioning element during the entire enter phase.
enterFrom String (Default: '') Classes to add to the transitioning element before the enter phase starts.
enterTo String (Default: '') Classes to add to the transitioning element immediately after the enter phase starts.
leave String (Default: '') Classes to add to the transitioning element during the entire leave phase.
leaveFrom String (Default: '') Classes to add to the transitioning element before the leave phase starts.
leaveTo String (Default: '') Classes to add to the transitioning element immediately after the leave phase starts.
beforeEnter Function Callback which is called before we start the enter transition.
afterEnter Function Callback which is called after we finished the enter transition.
beforeLeave Function Callback which is called before we start the leave transition.
afterLeave Function Callback which is called after we finished the leave transition.

Popover

Popover are built using Button and Panel components which are wrapped in Popover

Markup

<hux-popover>
   <hux-popover-button>
      <button class="flex w-full text-left mb-4">
         <span class="flex-grow font-semibold">Open Popover</span>
         <svg class="text-indigo-600 w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
         </svg>
      </button>
   </hux-popover-button>
   <hux-popover-panel>
      panel content...
   </hux-popover-panel>
</hux-popover>