vuetifyjs / vuetify

🐉 Vue Component Framework
https://vuetifyjs.com
MIT License
39.59k stars 6.94k forks source link

[Bug Report][3.1.11] Accessibility: VTextField using the hide-details prop adds an 'aria-describedby' attribute referencing a non-existent element #17012

Open ryanzbartlett opened 1 year ago

ryanzbartlett commented 1 year ago

Environment

Vuetify Version: 3.1.11 Vue Version: 3.2.47 Browsers: Chrome 111.0.0.0 OS: Mac OS 10.15.7

Steps to reproduce

Use the hide-details (or hide-details="auto") prop on a VTextField component.

Expected Behavior

The aria-describedby attribute should not be present, or should be empty or null.

Actual Behavior

The aria-describedby attribute refers to a messages element that doesn't exist, causing accessibility check errors.

Reproduction Link

https://play.vuetifyjs.com/#...

chrisnruud commented 1 year ago

Came here to report this as well.

lukycody commented 1 year ago

Hey there, we encountered a similiar problem in our vuetify project. As our issue (#17730) was closed recently in favor of this one, let me just add:

As far as I could tell, the issue (not found/matching aria-describedBy element) is unrelated to the "hide-details" prop, that was described as reproduction step here. It occurs without it aswell. So you might want to consider it and have a look at #17730 for a detailed description with code and screenshots. Cheers.

K-Schaeffer commented 10 months ago

Hi,

This is indeed happening with hide-details, I also noticed that this is an issue with textarea as well, but you don't need to pass anything, its default behavior is already breaking the aria-describedby. I'm investigating to figure why.

By the way, I couldn't reproduce the issue on a v-text-field with rules as mentioned on #17730 , I also ran a lighthouse analysis locally and it didn't show any error related to that, testing with screen reader it worked as expected too. Not sure if im missing something, but for now I'll focus on the reproducible scenario: WIth the prop on VTextfield and on VTextarea default.

lukycody commented 10 months ago

@K-Schaeffer Did some further testing with your feedback and encountered, that in our case the dirty prop was problematic and caused the aria-described problem. Removing it also removed the error. (The "dirty" appearance is the default for the v-selects (label is fixed on top), so we used dirty on the v-text-fields to get the same look - and would like to keep the same appearance)

However, an exception comes with text-fields with type="date" for the datepicker. There it exists even without the dirty prob. Could you try this on your end again?

Here's an code example of how we used the text-field btw:

<v-col sm="12" md="6">
    <v-card-text>
        <fieldset>
          <legend
            class="custom-legend bg-custom-lighten-2 ma-2 rounded"
          >
            <div class="d-flex mx-1 align-center">
              <v-icon icon="mdi-mail" class="mr-1"> </v-icon>
              <h3>Kontaktdaten</h3>
            </div>
          </legend>
          <v-container>
            <v-text-field
              v-model="telefonnr"
              label="Telefon*"
              color="primary"
              variant="outlined"
              density="comfortable"
              dirty
              :rules="[
                rules.required(telefonnr, 'Telefonnummer'),
                rules.telefonnummer,
              ]"
              validate-on="input"
            ></v-text-field>
            <v-text-field
              v-model="email"
              label="E-Mail*"
              type="email"
              variant="outlined"
              color="primary"
              density="comfortable"
              dirty
              :rules="[
                rules.required(email, 'E-Mail-Adresse'),
                rules.email,
              ]"
              validate-on="input"
            ></v-text-field>
          </v-container>
         </fieldset>
    </v-card-text>
</v-col>
johnleider commented 7 months ago

I've done some digging on this and it stems from our generation of a messagesId that's passed through a scoped slot. This needs to check if messages are available to show. It's a bit involved unfortunately, but it's on my radar.

hermes85pl commented 1 month ago

Additionally, there still is an empty label element if you don't specify the label property, hence if you want to put an external label by yourself (along with other details), you end up with two label elements for the same field (i.e. your custom one, and the hidden empty label rendered by Vuetify), which affects accessibility.

@johnleider, please also take this into consideration when tackling this issue.