ariaTarget for CustomField

According to the documentation, FormLayout uses the ariaTarget property to associate the field label with the proper HTML element within a Component. (for WCAG compliance)
Is there a way to utilize this mechanism with a CustomField? The documentation makes a passing reference to this, but doesn’t elaborate on how to do it.

Not really, as the use case described in the FormLayout docs is for composite fields consisting of multiple inputs, each of which needs its own unique aria-label, so it wouldn’t make sense to associate the FormItem’s label with all of them.

I think the only feasible approach is for your CustomField to provide its own API for setting aria-labels to each sub-field.

(The documentation could certainly be more clear on this matter.)

With that approach, I can’t use the addFormItem() method that constructs the Label for me. I have to create my own Label component and link it to the proper sub-component of my CustomField.

It’s more lines of code, but I tested and it does work.

Well, I mean, you don’t have to create your own label component, you just need to set accessible labels on the input(s) in your CustomField separately from the label provided to addFormItem.

Actually, could you share a screenshot or just describe your CustomField? There are so many ways to use it that it’s a bit difficult to give advice without knowing more.

I am not sure what you are looking for, but here is an example accessible composite field implemented with CustomField. Perhaps it is good food for thought.

https://v-herd.eu/tatulund-addons/duration

Here’s the initial header of my class. The divInner contains the emailField plus some other Badges that get added dynamically at runtime.

@Tag("div")
public class CelEmailList extends CustomField<String>
   implements HasValidator<String>
{
   protected Div divInner;
   protected Div divHelper;
   protected EmailField emailField;
   protected int maxAddresses;

What I’d like to be able to do is to add this to a FormLayout like any other component…

formLayout.addFormItem(new CelEmailList(), "Email Addresses");

… and then have the generated Label linked via aria attributes to the internal EmailField of the CelEmailList (well actually the <input> element within the EmailField). From what I can tell, the FormLayout does this automatically on the client side using the ariaTarget property and some other client-side smarts.

The workaround involves constructing my own NativeLabel, setting the id and aria attributes manually, and then calling addFormItem() with the alternative parameter signature, passing the NativeLabel as the second parameter instead of the label text.

var label = new NativeLabel("Email Addresses");
label.setId("lbl-demo");
var emailList = new CelEmailList();
emailList.getEmailField().setAriaLabelledBy("lbl-demo");
formLayout.addFormItem(emailList, label);

There’s nothing wrong with this, it’s just a lot of fiddly bookkeeping.

In your case, I don’t think you need a Custom field. You should probably use an AbstractCompositeField. The CustomField only add a layer that you don’t need ( a label, error message,…).

If the custom field is only ever used wrapped in a FormItem, then the label etc provided by CustomField are not really needed. Otherwise, if you create your own layout for the field, it can get tricky to make it align correctly on the same row with other fields, which CustomField solves for you.

I was actually thinking of something as simple as

var emailList = new CelEmailList();
emailList.getEmailField().setAriaLabel("Email Addresses");
formLayout.addFormItem(emailList, emailList.getAriaLabel());

and implement the aria-label API in your CustomField as follows:

public static class CelEmailList extends CustomField<String> {

    private EmailField emailField;
    
    public CelEmailList() {
        emailField = new EmailField();
    }
    
    public void setAriaLabel(String ariaLabel) {
        emailField.setAriaLabel(ariaLabel);
    }
    
    public String getAriaLabel() {
        return emailField.getAriaLabel().orElse(null);
    }

That way you’re using the layout, labels, errors, etc, provided by CustomField, and the native input gets the correct aria-label.

It would be nice if CustomField/FormItem could somehow associate the label element correctly in cases where there really is just a single input inside. Perhaps, if CustomField did have the ariaTarget property, it could provide an internal method for specifying either an appropriate element directly (like an <input>) or a Vaadin field component that provides its own ariaTarget.

Ultimately we made our custom field implement the HasAriaLabel interface, and then the implementation delegates it to the nested EmailField like your example above.

Our developers still need to be aware that this custom field needs special attention when used in FormLayouts due to the need to manually manage the aria-label link. It’s very easy for the developers to forget this, because except for WCAG everything will still otherwise look and work correctly. If the CustomField API had some support for the aria-label linking, then there would be no need for the special code treatment.

Yes, that would definitely be beneficial.

We’re actually planning on getting rid of the need to wrap fields into FormItems for side-label rendering in V25. Once that feature is in place, you will be able to just use the CustomField’s normal setLabel API (or the constructor overload) to set the label, and then assign the aria-label by overriding the setLabel implementation in your custom field.