Tips for enabling tab focus on concealed checkboxes with labels that are visible

I have a unique component that generates a pill check group. The checkboxes are hidden, while the labels are displayed as nicely formatted boxes in checked and unchecked states. Check out the InputCheckGroupPill.vue component below:

<div class="grid grid-cols-3 sm:grid-cols-4">
            <div v-for="(option, index) in options" :key="option[valueAttribute]">

                <div class="text-sm ">
                    <input :id="'check-option-' + option[valueAttribute] + index"
                           :aria-describedby="'check-label-' + option[valueAttribute] + index"
                           :aria-activedescendant="'check-label-' + option[valueAttribute] + index"
                           :aria-labelledby="'check-label-' + option[valueAttribute] + index"
                           :value="option[valueAttribute]"
                           v-model="selectedOptions"
                           class="hidden"
                           type="checkbox"/>
                    <label :id="'check-label-' + option[valueAttribute] + index"
                           :for="'check-option-' + option[valueAttribute] + index"
                           :class="[ selectedOptions.includes(option[valueAttribute]) ? 'bg-primary-600 text-white hover:bg-primary-500 border border-r-1 border-gray-100' : 'ring-1 ring-inset ring-gray-300 bg-white text-gray-900 hover:bg-gray-50', index === 0 ? 'rounded-l-md': '', index === options.length-1 ? 'rounded-r-md': '', 'flex items-center justify-center  py-3 px-3 text-sm font-semibold uppercase sm:flex-1 focus-visible:ring-2 focus-visible:ring-primary-600 focus-visible:ring-offset-2 cursor-pointer']">
                        {{option[labelAttribute]}}
                    </label>

                </div>
            </div>
        </div>

Below is a visual representation of the component:

https://i.sstatic.net/cE9yE.png

However, I am facing an issue where the checkboxes are being skipped when navigating using the tab key.

I have tried various ARIA descriptors from MDN without success. Can you offer any assistance?

Please note that the component functions correctly with mouse interaction, but I need it to be keyboard-friendly too.

The technologies used are VueJs for functionality and Tailwind CSS for styling.

Answer №1

Instead of using display: none to hide the checkbox, consider utilizing sr-only to visually conceal the element while ensuring it remains accessible for screen readers and similar tools. This approach also allows for using peer styling when the element is in focus, such as:

<input … class="… peer"/>
<label … class="… peer-focus-visible:ring-2 peer-focus-visible:ring-primary-600 peer-focus-visible:ring-offset-2"/>

Vue.createApp({
  data() {
    return {
      selectedOptions: [],
      options: {
        foo: {
          valueAttribute: 'foo',
          labelAttribute: 'Foo',
        },
        bar: {
          valueAttribute: 'bar',
          labelAttribute: 'Bar',
        },
      },
    };
  },
}).mount('#app');

tailwind.config = {
  theme: {
    extend: {
      colors: {
        primary: tailwind.colors.blue,
      }
    }
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.3.4/vue.global.prod.min.js" integrity="sha512-39BSQXI5q1XlvVhLfFRidKG8KM6Tr6VS/XSnNo6N/A0ZXexHCeoUI/s+ulujQy3UREjoLNrMnFat8VI0mMugWA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdn.tailwindcss.com/3.3.2"></script>

<div id="app">
  <div class="grid grid-cols-3 sm:grid-cols-4">
    <div v-for="(option, index) in options" :key="option.valueAttribute">

      <div class="text-sm ">
        <input
          :id="'check-option-' + option.valueAttribute + index"
          :aria-describedby="'check-label-' + option.valueAttribute + index"
          :aria-activedescendant="'check-label-' + option.valueAttribute + index"
          :aria-labelledby="'check-label-' + option.valueAttribute + index"
          :value="option.valueAttribute"
          v-model="selectedOptions"
          class="sr-only peer"
          type="checkbox"
        />
        <label
          :id="'check-label-' + option.valueAttribute + index"
          :for="'check-option-' + option.valueAttribute + index"
          :class="[
            selectedOptions.includes(option.valueAttribute)
              ? 'bg-primary-600 text-white hover:bg-primary-500 border border-r-1 border-gray-100'
              : 'ring-1 ring-inset ring-gray-300 bg-white text-gray-900 hover:bg-gray-50',
            index === 0
              ? 'rounded-l-md'
              : '',
            index === options.length-1 ?
              'rounded-r-md'
              : '',
            'flex items-center justify-center py-3 px-3 text-sm font-semibold uppercase sm:flex-1 peer-focus-visible:ring-2 peer-focus-visible:ring-primary-600 peer-focus-visible:ring-offset-2 cursor-pointer'
            ]"
        >
          {{ option.labelAttribute }}
        </label>
      </div>
    </div>
  </div>
</div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Activate the Dart checkbox to ensure it is checked

Is there a way to programmatically check a CheckBox element? I've attempted using Click();, but it hasn't worked. I've also looked for a method like .setChecked(true); without any luck. Could it be because I'm utilizing the checkbox as ...

Prevent Scrolling of Body Content within a Specified Div

In my current situation, I am dealing with a large number of divs (over 300) that are being used as part of an interactive background. The issue arises when viewing the page on mobile versus desktop – there are too many divs on desktop, causing excessive ...

What are some ways to expand the width of a MaterialUI form control if no value has been chosen?

I am currently working on a project where I need a dropdown menu component with specific selections. However, the layout appears to be cramped and I'm struggling to adjust the width. Additionally, I've been unsuccessful in changing the font size ...

Issue with aligning columns to the right in Bootstrap 4

Currently, I am utilizing Bootstrap v4.0.0-alpha.6 In a single row, I have three columns displayed and I am looking to swap the first column with the last column specifically in md screen size but not in sm/xs. Here is how I envision it in desktop mode: ...

`Manipulating appearance with jQuery`

I am looking for a way to dynamically set CSS styles to certain elements using jQuery based on the background color of a specific div with an id of "TestDiv". This functionality is crucial due to our website's theme engine that allows users to change ...

Overlay jQuery Accordion

I am currently working on an accordion to display old blog posts. However, when using a tab, the section below either moves or jumps around. I want the tab to lay over the rows below it without affecting their position. I have tried various solutions in ...

Font family experiencing compatibility issues with font face

The prominent "C" at the center of the page, as well as the H1 ('Choose The Right...) should be displayed using the "Pirulen" font-family. My initial attempt was to implement the traditional @font-face method for CSS, followed by a more advanced appr ...

Tips on showing a success notification following form submission in HTML

I have crafted this code utilizing a combination of bootstrap, python, and html. I have omitted the css portion for brevity, but I can certainly provide it if necessary. My aim is to be able to send an email using smtplib and flask, with the added function ...

Tips on containing text within a div box without exceeding its boundaries

I've been struggling with containing the text in my display area. No matter what I try, the text keeps overflowing and it's driving me crazy. I've researched various solutions like using word-wrap: break-word;, adjusting width manually, but ...

Having trouble with the functionality of the jQuery `has()` method?

Consider the following HTML code snippet: <div class="comment"> <span class="test">some content here</span> <p>Lorem ipsum</p> </div> <div class="comment"> <p>Lorem ipsum</p> </div> The ob ...

Issue with deletion request in Vue InertiaJS Laravel system: still not functioning as expected

While attempting to send a deletion request to users.destroy, I ensured that the ids array returns at least one element. However, Laravel throws an error stating: count(): Argument #1 ($value) must be of type Countable|array, string given Users/Index.vue ...

Is there a way to detect unnecessary or unused inline CSS styles that are not needed or blank?

Is there a way to detect unnecessary CSS inline styles that are typed but not actually needed? For example, in a .js file: line: { borderBottom: '1px #ddd solid', paddingBottom: '5px', backgroundColor: 'white', ...

Ways to Conceal Information in Angular2

On my website, I have a layout with three tabs. In the third tab, I've implemented an ng-select tag. My goal is to only display the 1st ng-select tag initially, while keeping the other two hidden until the user selects data in the 1st tag. For referen ...

Choosing an element with JavaScript

var displayedImage = document.querySelector('.displayed-img'); var thumbBar = document.querySelector('.thumb-bar'); btn = document.querySelector('button'); var overlay = document.querySelector('.overlay'); /* Itera ...

Maintain the aspect ratio of an image within a flex container when the height is adjusted

I'm currently facing an issue with an image in a flex container. My goal is to maintain the image's ratio when the height of the container or window is decreased or resized. Check out this sample fiddle html, body { height: 100%; } .wrappe ...

What is the process for creating a selector that links to an element that has been dynamically generated?

Can anyone help me figure out how to create a selector that links to a dynamically created element without using an event on the dynamic element? By dynamically created element, I mean an element that is not present in the HTML at the beginning. I know t ...

PHP Form Functions Properly on Firefox, but Encounters Issues on IE and Chrome

I'm having an issue with a form I created to send to my email. The form works fine in Firefox, but it's not functioning properly in Chrome or Internet Explorer. Any assistance would be greatly appreciated! EDIT The problem is that the php code i ...

What is the best way to enable a clickable YouTube iframe that is positioned behind an image using z-index?

Currently, I'm working on a project for a client that involves showcasing their YouTube videos on a webpage. I've come up with a creative solution using z-index to place the YouTube iframes inside images of televisions. However, I've encount ...

Customized CSS scrollbar within a specific div

Is it possible to apply CSS to customize the scroll bar of a specific div without affecting the entire page layout? ...

When multiple input fields with an iterative design are using the same onChange() function, the specific event.target.values for each input

I'm in the process of developing a dynamic select button that adjusts based on the information entered into the iterative input fields I've set up. These input fields all utilize the same onChange() function. for (let i = 0; i < selectCount; i ...