Skip to main

Vanilla-headless Web Components

Completely un-styled, fully accessible UI Web Components library, with fully unopinionated css styling.

Installation

To use the TailwindCSS Stripes Plugin, you need to have TailwindCSS installed in your project. If you don't have it yet, you can follow the installation guide to set it up.

Once you have TailwindCSS installed, you can add the Stripes Plugin to your project using pnpm, npm or yarn:

Using pnpm

pnpm add  vanilla-headless

Using npm

npm install vanilla-headless 

Using yarn

yarn add vanilla-headless

Using cdn

https://unpkg.com/vanilla-headless@latest
https://cdn.jsdelivr.net/npm/vanilla-headless@latest

Use

import "vanilla-headless"

That's all, no other javascript required. Just wrap you aria compliant markup with the appropriate tag and attributes.

The example files is using TailwindCSS but is not required with TailwindUI

Web Components

The web component is basically a wrapper around your semantic html. At it's most basic it will even work without any css.

Popover with aria keyboard navigation

The popover element makes it easy to show and hide html elements on page. This work great for dropdown, menus and popover.

Events:

  • Toggle dropdown on click event.
  • Toggle dropdown on keyEvent Space and Enter keys
  • Close dropdown keyEvent Esc key.
  • Close dropdown on click outside of element.

Requirements:

  • Button:
    • must be typeof button
    • must have attributes of aria-haspopup and aria-expanded
    • ID must have same value as dropdown labelledby
  • Dropdown
    • must have attributes of aria-labelledby

Unstyled popover component

Example
Content

<headless-popover class="relative">
  <button aria-expanded="false" id="popover" aria-haspopup="true">Button</button>
  <div aria-labelledby="popover">
    Content
  </div>
</headless-popover>

Styled popover component with tailwindcss


<headless-popover class="relative text-gray-700" offset="0 10" placement="bottom top" popper>
  <button
    aria-expanded="false"
    aria-haspopup="true"
    class="inline-flex justify-between w-full rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 
    focus:ring-offset-gray-100 focus:ring-primary-500"
    id="popover"
    type="button"
  >
    Popover
    <!-- Heroicon name: solid/chevron-down -->
    <svg aria-hidden="true" class="-mr-1 ml-2 h-5 w-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
      <path clip-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" fill-rule="evenodd" />
    </svg>
  </button>
  <div aria-labelledby="popover" class="absolute z-10 w-screen max-w-sm transform px-4 sm:px-0">
    <div class="overflow-hidden rounded-lg shadow-lg ring-1 ring-black ring-opacity-5">
      <div class="relative grid gap-8 bg-white p-7">
        <a class="-m-3 flex items-center rounded-lg p-2 transition duration-150 ease-in-out hover:bg-gray-50 focus:outline-none focus-visible:ring focus-visible:ring-primary-500 focus-visible:ring-opacity-50" href="#">
          <span>
            <svg aria-hidden="true" fill="none" height="48" viewBox="0 0 48 48" width="48" xmlns="http://www.w3.org/2000/svg" class=text-primary-500>
              <rect class="fill-primary-500/20" height="48" rx="8" width="48"></rect>
              <path d="M24 11L35.2583 17.5V30.5L24 37L12.7417 30.5V17.5L24 11Z" stroke="currentColor" stroke-width="2"></path>
              <path clip-rule="evenodd" d="M16.7417 19.8094V28.1906L24 32.3812L31.2584 28.1906V19.8094L24 15.6188L16.7417 19.8094Z" fill-rule="evenodd" stroke="currentColor" stroke-width="2"></path>
              <path clip-rule="evenodd" d="M20.7417 22.1196V25.882L24 27.7632L27.2584 25.882V22.1196L24 20.2384L20.7417 22.1196Z" fill-rule="evenodd" stroke="currentColor" stroke-width="2"></path>
            </svg>
          </span>
          <span class="ml-2 text-gray-600"> Lorem ipsum dolor sit amet, consectetur. </span>
        </a>
        <a class="-m-3 flex items-center rounded-lg p-2 transition duration-150 ease-in-out hover:bg-gray-50 focus:outline-none focus-visible:ring focus-visible:ring-primary-500 focus-visible:ring-opacity-50" href="#">
          <span>
            <svg aria-hidden="true" fill="none" height="48" viewBox="0 0 48 48" width="48" xmlns="http://www.w3.org/2000/svg" class=text-primary-500>
              <rect class="fill-primary-500/20" height="48" rx="8" width="48"></rect>
              <path d="M24 11L35.2583 17.5V30.5L24 37L12.7417 30.5V17.5L24 11Z" stroke="currentColor" stroke-width="2"></path>
              <path clip-rule="evenodd" d="M16.7417 19.8094V28.1906L24 32.3812L31.2584 28.1906V19.8094L24 15.6188L16.7417 19.8094Z" fill-rule="evenodd" stroke="currentColor" stroke-width="2"></path>
              <path clip-rule="evenodd" d="M20.7417 22.1196V25.882L24 27.7632L27.2584 25.882V22.1196L24 20.2384L20.7417 22.1196Z" fill-rule="evenodd" stroke="currentColor" stroke-width="2"></path>
            </svg>
          </span>
          <span class="ml-2 text-gray-600"> Lorem ipsum dolor sit amet, consectetur. </span>
        </a>
        <a class="-m-3 flex items-center rounded-lg p-2 transition duration-150 ease-in-out hover:bg-gray-50 focus:outline-none focus-visible:ring focus-visible:ring-primary-500 focus-visible:ring-opacity-50" href="#">
          <span>
            <svg aria-hidden="true" fill="none" height="48" viewBox="0 0 48 48" width="48" xmlns="http://www.w3.org/2000/svg" class=text-primary-500>
              <rect class="fill-primary-500/20" height="48" rx="8" width="48"></rect>
              <path d="M24 11L35.2583 17.5V30.5L24 37L12.7417 30.5V17.5L24 11Z" stroke="currentColor" stroke-width="2"></path>
              <path clip-rule="evenodd" d="M16.7417 19.8094V28.1906L24 32.3812L31.2584 28.1906V19.8094L24 15.6188L16.7417 19.8094Z" fill-rule="evenodd" stroke="currentColor" stroke-width="2"></path>
              <path clip-rule="evenodd" d="M20.7417 22.1196V25.882L24 27.7632L27.2584 25.882V22.1196L24 20.2384L20.7417 22.1196Z" fill-rule="evenodd" stroke="currentColor" stroke-width="2"></path>
            </svg>
          </span>
          <span class="ml-2 text-gray-600"> Lorem ipsum dolor sit amet, consectetur. </span>
        </a>
      </div>
    </div>
  </div>
</headless-popover>

Dropdown with aria keyboard navigation

The dropdown is at the core the same as the popover element with the only difference that it adds additional functionality to navigate menu elements via keyboard and adding aria-current attribute to track selected element

Events:

  • Toggle dropdown on click event.
  • Toggle dropdown on keyEvent Space and Enter keys
  • Navigate up and down with Tab, Shift + Tab, DownArrow, UpArrow, RightArrow, LeftArrow keys
  • Close dropdown keyEvent Esc key.
  • Close dropdown on click outside of element.

Requirements:

  • Button:
    • must be typeof button
    • must have attributes of aria-haspopup and aria-expanded
    • ID must have same value as dropdown labelledby
  • Dropdown
    • must have attributes of aria-labelledby
    • dropdown require at least 1 anchor or button tag with attribute role="menuitem"

Unstyled Dropdown menu

Example

<headless-dropdown>
  <button aria-expanded="false" aria-haspopup="true" type="button" id="dropdown">Button</button>
  <div aria-labelledby="dropdown">
    <a href="#" role="menuitem">Link</a>
    <a href="#" role="menuitem">Link</a>
    <a href="#" role="menuitem">Link</a>
    <a href="#" role="menuitem">Link</a>
  </div>
</headless-dropdown>

Styled Dropdown menu with Tailwindcss

Example

<headless-dropdown class="relative inline-block text-left" offset="0 10" placement="bottom-end top-end" popper>
  <button
    type="button"
    class="inline-flex justify-center w-full rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-100 focus:ring-indigo-500"
    id="menu-button"
    aria-expanded="false"
    aria-haspopup="true"
  >
    USE VANILLA HEADLESS
    <svg class="-mr-1 ml-2 h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
      <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
    </svg>
  </button>
  <div class="w-56 absolute rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none shadow-2xl" role="menu" aria-orientation="vertical" aria-labelledby="menu-button" tabindex="-1">
    <div class="py-1" role="none">
      <a href="#" class="text-gray-700 block px-4 py-2 text-sm" role="menuitem" tabindex="-1" id="menu-item-0">GITHUB</a>
      <a href="#" class="text-gray-700 block px-4 py-2 text-sm" role="menuitem" tabindex="-1" id="menu-item-1">NPM</a>
      <a href="#" class="text-gray-700 block px-4 py-2 text-sm" role="menuitem" tabindex="-1" id="menu-item-2">YARN</a>
      <a href="#" class="text-gray-700 block px-4 py-2 text-sm" role="menuitem" tabindex="-1" id="menu-item-2">UNPKG CDN</a>
    </div>
  </div>
</headless-dropdown>

Disclosure with aria keyboard navigation

The Disclosure element is ideal for hide and showing a list of elements. Best used for components like for Q&A's.

Events:

  • Toggle panels on click event.
  • Toggle panels on keyEvent Space and Enter
  • Navigate up and down with Tab, Shift + Tab, DownArrow, UpArrow

Requirements:

  • Button:
    • must be typeof button
    • must have attributes of aria-controls and aria-expanded
  • Dropdown
    • must have a ID matching aria-controls

Unstyled Disclosure

Example
Park at the nearest available parking meter without paying the meter and call 999-999-9999 to report the problem. We will note and approve your alternate location and will investigate the cause of the shortage in your assigned facility.
You should come to the Parking office and report the loss. There is a fee to replace your lost permit. However, if your permit was stolen, a copy of a police report needs to be submitted along with a stolen parking permit form for a fee replacement exemption.

<headless-disclosure>
  <dl>
    <dt>
      <button aria-controls="faq_1_desc" aria-expanded="false" type="button">
        What do I do if I have a permit for an assigned lot, but can't find a space there? <span style="display: inline-flex;"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="w-5 h-5"><path
        fill-rule="evenodd" d="M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z" clip-rule="evenodd" /></svg></span>
      </button>
    </dt>
    <dd>
      <div id="faq_1_desc">
        Park at the nearest available parking meter without paying the meter and call 999-999-9999 to report the problem. We will note and approve your alternate location and will investigate the cause of the shortage in your assigned
        facility.
      </div>
    </dd>
    <dt>
      <button aria-controls="faq_2_desc" aria-expanded="false" type="button">
        What do I do if I lose my permit or if my permit is stolen?
        <span style="display: inline-flex;"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="w-5 h-5"> 
          <path fill-rule="evenodd" d="M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z"
                clip-rule="evenodd" /></svg></span>
      </button>
    </dt>
    <dd>
      <div id="faq_2_desc">
        You should come to the Parking office and report the loss. There is a fee to replace your lost permit. However, if your permit was stolen, a copy of a police report needs to be submitted along with a stolen parking permit form for a
        fee replacement exemption.
      </div>
    </dd>
  </dl>
</headless-disclosure>

Styled disclosure with Tailwindcss

Example
Park at the nearest available parking meter without paying the meter and call 999-999-9999 to report the problem. We will note and approve your alternate location and will investigate the cause of the shortage in your assigned facility.
You should come to the Parking office and report the loss. There is a fee to replace your lost permit. However, if your permit was stolen, a copy of a police report needs to be submitted along with a stolen parking permit form for a fee replacement exemption.
All facilities are restricted from 2:00 am - 6:00 am on all days. No exceptions are made for any holiday or recess except those officially listed as a Holidays in the calendar. Please note: 24-hour rental spaces, 24-hour rental lots, and disabled parking is enforced at all times.
Some parking facility restrictions differ from others. Be sure to take note of the signs at each lot entrance.

<headless-disclosure class="max-w-md block rounded-md bg-white p-2">
  <dl class="faq">
    <dt>
      <button
        aria-controls="faq1_desc"
        aria-expanded="true"
        class="flex w-full rounded-md bg-primary-100 px-4 py-2 text-left text-sm font-medium text-primary-900 hover:bg-primary-200 focus:outline-none focus-visible:ring focus-visible:ring-primary-500 focus-visible:ring-opacity-75 mb-2"
        type="button"
      >
        What do I do if I have a permit for an assigned lot, but can't find a space there?
      </button>
    </dt>
    <dd>
      <div class="px-4 pt-4 pb-2 text-sm text-gray-500" id="faq1_desc">
        Park at the nearest available parking meter without paying the meter and call 999-999-9999 to report the problem. We will note and approve your alternate location and will investigate the cause of the shortage in your assigned
        facility.
      </div>
    </dd>
    <dt>
      <button
        aria-controls="faq2_desc"
        aria-expanded="false"
        class="flex w-full rounded-md bg-primary-100 px-4 py-2 text-left text-sm font-medium text-primary-900 hover:bg-primary-200 focus:outline-none focus-visible:ring focus-visible:ring-primary-500 focus-visible:ring-opacity-75 mb-2"
        type="button"
      >
        What do I do if I lose my permit or if my permit is stolen?
      </button>
    </dt>
    <dd>
      <div class="px-4 pt-4 pb-2 text-sm text-gray-500" id="faq2_desc">
        You should come to the Parking office and report the loss. There is a fee to replace your lost permit. However, if your permit was stolen, a copy of a police report needs to be submitted along with a stolen parking permit form for a
        fee replacement exemption.
      </div>
    </dd>
    <dt>
      <button
        aria-controls="faq3_desc"
        aria-expanded="false"
        class="flex w-full rounded-md bg-primary-100 px-4 py-2 text-left text-sm font-medium text-primary-900 hover:bg-primary-200 focus:outline-none focus-visible:ring focus-visible:ring-primary-500 focus-visible:ring-opacity-75 mb-2"
        type="button"
      >
        Is there free parking on holidays?
      </button>
    </dt>
    <dd>
      <div class="px-4 pt-4 pb-2 text-sm text-gray-500" id="faq3_desc">
        All facilities are restricted from 2:00 am - 6:00 am on all days. No exceptions are made for any holiday or recess except those officially listed as a
        <q> Holidays </q>
        in the calendar. Please note: 24-hour rental spaces, 24-hour rental lots, and disabled parking is enforced at all times.
      </div>
    </dd>
    <dt>
      <button
        aria-controls="faq4_desc"
        aria-expanded="false"
        class="flex w-full rounded-md bg-primary-100 px-4 py-2 text-left text-sm font-medium text-primary-900 hover:bg-primary-200 focus:outline-none focus-visible:ring focus-visible:ring-primary-500 focus-visible:ring-opacity-75 mb-2"
        type="button"
      >
        Do all parking facilities have the same enforcement rules?
      </button>
    </dt>
    <dd>
      <div class="px-4 pt-4 pb-2 text-sm text-gray-500" id="faq4_desc">
        Some parking facility restrictions differ from others. Be sure to take note of the signs at each lot entrance.
      </div>
    </dd>
  </dl>
</headless-disclosure>

Tabs with aria keyboard navigation

The Tab element is ideal to show or hide content by use showing content on selected tab button.

Events:

  • Toggle panels on click event.
  • Toggle panels on keyEvent Space and Enter
  • Navigate up and down with Tab, Shift + Tab, DownArrow, UpArrow

Requirements:

  • Button:
    • must be typeof button
    • must have attributes of aria-controls and aria-expanded
  • Dropdown
    • must have a ID matching aria-controls

Important: To prevent content shift add hidden to corresponding aria-controlled element

Unstyled Tabs

Example

Tab 1

lorem content for tab item 1


<headless-tabs>
  <div>
    <button
      aria-controls="tab-1-1"
      aria-expanded="true"
      type="button"
      style="background-color: lightgray; padding: 2px 5px; border-radius: 4px; color: #111; font-size: 14px; "
    >
      Tab 1
    </button>
    <button
      aria-controls="tab-2-1"
      aria-expanded="false"
      type="button"
      style="background-color: lightgray; padding: 2px 5px; border-radius: 4px; color: #111; font-size: 14px; "
    >
      Tab 2
    </button>
    <button
      aria-controls="tab-3-1"
      aria-expanded="false"
      type="button"
      style="background-color: lightgray; padding: 2px 5px; border-radius: 4px; color: #111; font-size: 14px; "
    >
      Tab 3
    </button>
    <button
      aria-controls="tab-4-1"
      aria-expanded="false"
      type="button"
      style="background-color: lightgray; padding: 2px 5px; border-radius: 4px; color: #111; font-size: 14px; "
    >
      Tab 4
    </button>
  </div>
  <div id="tab-1-1">
    <h3>Tab 1</h3>
    <p>
      lorem content for tab item 1
    </p>
  </div>
  <div hidden id="tab-2-1">
    <h3>Tab 2</h3>
    <p>
      lorem content for tab item 2
    </p>
  </div>
  <div hidden id="tab-3-1">
    <h3>Tab 3</h3>
    <p>
      lorem content for tab item 3
    </p>
  </div>
  <div hidden id="tab-4-1">
    <h3>Tab 4</h3>
    <p>
      lorem content for tab item 4
    </p>
  </div>
</headless-tabs>

Styled tabs with Tailwindcss

Example

Tab 1

lorem content for tab item 1


<headless-tabs class="mx-auto my-20 block w-full max-w-md rounded-md bg-white p-2 shadow-2xl shadow-primary-500/25">
  <div class="flex space-x-2">
    <button
      aria-controls="tab-1"
      aria-expanded="true"
      class="flex w-full rounded-md bg-blue-100 px-4 py-2 text-left text-sm font-medium text-blue-900 hover:bg-blue-200 focus:outline-none focus-visible:ring focus-visible:ring-blue-500 focus-visible:ring-opacity-75 mb-2"
      type="button"
    >
      Tab 1
    </button>
    <button
      aria-controls="tab-2"
      aria-expanded="false"
      class="flex w-full rounded-md bg-blue-100 px-4 py-2 text-left text-sm font-medium text-blue-900 hover:bg-blue-200 focus:outline-none focus-visible:ring focus-visible:ring-blue-500 focus-visible:ring-opacity-75 mb-2"
      type="button"
    >
      Tab 2
    </button>
    <button
      aria-controls="tab-3"
      aria-expanded="false"
      class="flex w-full rounded-md bg-blue-100 px-4 py-2 text-left text-sm font-medium text-blue-900 hover:bg-blue-200 focus:outline-none focus-visible:ring focus-visible:ring-blue-500 focus-visible:ring-opacity-75 mb-2"
      type="button"
    >
      Tab 3
    </button>
    <button
      aria-controls="tab-4"
      aria-expanded="false"
      class="flex w-full rounded-md bg-blue-100 px-4 py-2 text-left text-sm font-medium text-blue-900 hover:bg-blue-200 focus:outline-none focus-visible:ring focus-visible:ring-blue-500 focus-visible:ring-opacity-75 mb-2"
      type="button"
    >
      Tab 4
    </button>
  </div>
  <div class="px-4 text-sm text-gray-500" id="tab-1">
    <h3 class="text-xl font-bold text-gray-900 mt-2">Tab 1</h3>
    <p>
      lorem content for tab item 1
    </p>
  </div>
  <div hidden class="px-4 text-sm text-gray-500" id="tab-2">
    <h3 class="text-xl font-bold text-gray-900 mt-2">Tab 2</h3>
    <p>
      lorem content for tab item 2
    </p>
  </div>
  <div hidden class="px-4 text-sm text-gray-500" id="tab-3">
    <h3 class="text-xl font-bold text-gray-900 mt-2">Tab 3</h3>
    <p>
      lorem content for tab item 3
    </p>
  </div>
  <div hidden class="px-4 text-sm text-gray-500" id="tab-4">
    <h3 class="text-xl font-bold text-gray-900 mt-2">Tab 4</h3>
    <p>
      lorem content for tab item 4
    </p>
  </div>
</headless-tabs>

Navigation with aria keyboard interactions

This component allow you to add hamburger toggle functionality to your navigation by adding aria labels to button and the section you want to hide and show. The data attribute of data-state can be used to style or hide element.

Events:

  • Toggle mobile menu with mouse click events.
  • Toggle mobile menu pressing down on Enter and Space keys.
  • Close mobile menu pressing Esc Key.
  • Close mobile menu by clicking outside menu.
  • Add multiple data-state of open and close
  • Support two-way binding on state change of data-state

Requirements:

  • Button:
    • must be typeof button
    • must add an attribute of aria-expanded aria-controls
  • Mobile Menu
    • must have a html element with an id matching aria-controls

Unstyled navigation

Example

<headless-navigation>
  <button type="button" aria-expanded="false" aria-controls="menu">
    menu
  </button>
  <div id="menu">
    Dummy menu dropdown
  </div>
</headless-navigation>

Styled navigation with tailwindcss

Example

<headless-navigation class="relative z-50" popper>
  <nav class="relative w-full bg-white rounded-md py-2 flex justify-end">
    <button type="button" aria-expanded="false" aria-controls="menu" class="w-8 h-8 mr-10 border border-primary-900 flex justify-center items-center m-3 rounded-md">
      <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
        <path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" />
      </svg>
    </button>
    <div id="menu" class="bg-white absolute inset-x-0 rounded-md p-4 w-full h-[400px]">
      Dummy menu dropdown
    </div>
  </nav>
</headless-navigation>

Dark Mode Toggle button with keyboard interactions

The dark mode component will toggle between dark and light and save the result to localStorage.

Events:

  • Toggle theme button with mouse click events.
  • Toggle theme button pressing down on Enter and Space keys.
  • Adds a data-theme to root component

Requirements:

  • Button:
    • must be typeof button
    • There must be at least 1 headless-darkmode component on every page. It is recommended to use it with in a section that will be display on every page. Places like navigation or footer will work great.

Dark mode toggle

Example

<headless-darkmode class="inline-flex">
  <button type="button" class="px-4 py-2 flex justify-center space-x-2 inline-block rounded-md dark:bg-white dark:text-gray-600 bg-gray-700 text-gray-100 shadow-md">
    <svg style="width: 24px; height: 24px;" viewBox="0 0 24 24">
      <path
        fill="currentColor"
        d="M7.5,2C5.71,3.15 4.5,5.18 4.5,7.5C4.5,9.82 5.71,11.85 7.53,13C4.46,13 2,10.54 2,7.5A5.5,5.5 0 0,1 7.5,2M19.07,3.5L20.5,4.93L4.93,20.5L3.5,19.07L19.07,3.5M12.89,5.93L11.41,5L9.97,6L10.39,4.3L9,3.24L10.75,3.12L11.33,1.47L12,3.1L13.73,3.13L12.38,4.26L12.89,5.93M9.59,9.54L8.43,8.81L7.31,9.59L7.65,8.27L6.56,7.44L7.92,7.35L8.37,6.06L8.88,7.33L10.24,7.36L9.19,8.23L9.59,9.54M19,13.5A5.5,5.5 0 0,1 13.5,19C12.28,19 11.15,18.6 10.24,17.93L17.93,10.24C18.6,11.15 19,12.28 19,13.5M14.6,20.08L17.37,18.93L17.13,22.28L14.6,20.08M18.93,17.38L20.08,14.61L22.28,17.15L18.93,17.38M20.08,12.42L18.94,9.64L22.28,9.88L20.08,12.42M9.63,18.93L12.4,20.08L9.87,22.27L9.63,18.93Z"
      />
    </svg>
    <span>Dark Mode</span>
  </button>
</headless-darkmode>

Toggle Switch

The toggle component allow you to turn a button elements into toggle switch

Events

  • Toggle switch with mouse click event
  • Toggle switch by pressing down on Enter and Space keys.

Requirements

  • Button element with type of button
Example

<headless-toggle>
  <headless-toggle class="flex items-center group">
    <button
      aria-checked="true"
      class="group-data-switch-on:bg-primary-500 bg-gray-200 relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
      type="button"
    >
      <span class="sr-only">Use setting</span>
      <span aria-hidden="true" class="group-data-switch-on:translate-x-5 translate-x-0 pointer-events-none inline-block h-5 w-5 rounded-full bg-white shadow transform ring-0 transition ease-in-out duration-50" data-switch></span>
    </button>
  </headless-toggle>

Styling toggle state

Markup the button the way you want and adding data-switch to one or multiple elements. This will set the data attribute to "on" or "off". Now you can style, hide or show elements by styling data attribute. By default, this attribute will be added to the top level component.

headless-toggle[data-switch="on"] button[aria-checked] {
  background: indigo;
}

headless-toggle[data-switch="on"] span[aria-hidden="true"] {
  transform: translateX(20px);
}

Directives

Directives are markers on a DOM element to attach a specified behavior to that DOM element.

Button directive

The button directive just adds event listeners to set aria-pressed attributes to a button element. Just add is="headless-button" to button element. Use css to style button using css propery button[aria-pressed=true] or button[aria-pressed=false]

Events

  • Add aria-pressed="true | false" on keydown, keyup, mouse click

Requirements:

  • Must be a button element.
  • Just add is="headless-button" to button elements

ScrollTop with aria keyboard interactions (Extends HeadlessButton)

The scroll-to-top button makes it super easy to add this feature to your website. Just add a button and add the attribute of is="headless-scrolltop" and that is it.

Events:

  • Hide button on initial load.
  • Hide and show button on scroll.
  • Scroll to top on Mouse click.
  • Scroll to top on Keydown for Space, Enter and Ctrl + Home.

Requirements:

  • Button:
    • must be typeof button
    • must add an attribute of is="headless-scrolltop"

Example

<button type="button" is="headless-scrolltop">Scroll to top</button>

GoBack with aria keyboard interactions (Extends HeadlessButton)

The headless-goback directive allow you to turn a button into go to previous page button using window.history and adding the necessary aria indicators and events

Events:

  • Trigger element on mouse click event
  • Trigger element on keyboard event, when using Space or Enter
  • Automatically set aria-pressed to true and false
Example

<button type="button" is="headless-goback">Go Back</button>

PopperJs

PopperJs is already bundle in and only require an attribute of popper to work. PopperJs only works on Popover, DropDown and Navigation component.

Optional

  • Popper.js
    • Required: Add attribute of popper or popper="true" to enable popper.js
    • Change placement with attribute placement="bottom-end bottom-start"
    • Change offset with attribute offset="0 20"

Use with PopperJs

Attribute can be seperated by comma or empty space


<headless-dropdown popper placement="bottom-end bottom-start" ....
<headless-dropdown popper="true" placement="bottom-end,bottom-start" ....
<headless-dropdown popper offset="0 20" ....
<headless-dropdown popper="true" offset="0,20" ....

Contributing

Contributions to this plugin are welcome! If you encounter any issues, have feature requests, or want to improve the plugin, feel free to create a pull request or submit an issue on the GitHub repository.

Contributors

contrib

License

This project is licensed under the MIT License - see the LICENSE file for details.

©2024 DesignByCode, Inc. All rights reserved.

Design & Developed by DesignByCode