Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How is the accessible name determined when an element contains a slot? #93

Open
geoffrich opened this issue Sep 4, 2020 · 7 comments
Open
Assignees
Milestone

Comments

@geoffrich
Copy link

How is the accessible name determined for elements that contain slots? For example, look at the following HTML which defines a custom button element containing a slot.

<template id="button-template">
    <button><slot></slot></button>
</template>
<custom-button>Submit</custom-button>
<script>
    customElements.define(
    'custom-button',
    class extends HTMLElement {
        constructor() {
        super();
        const template = document.getElementById('button-template')
            .content;
        const shadowRoot = this.attachShadow({ mode: 'open' }).appendChild(
            template.cloneNode(true)
        );
        }
    }
    );
</script>

When inspecting the <button> element in the shadow root, both Chrome and Firefox say the accessible name is "Submit". However, I can't find anything in the accessible name mapping spec mentioning slots. Per step F.iii, each child node of the button would be recursively examined to determine the name. So, the text alternative for the slot would need to be determined. The slot does not have any childNodes, so the process stops there. It seems like assignedNodes would also need to be examined to compute the accessible name.

const slot = document.querySelector('custom-button').shadowRoot.querySelector('slot')
console.log(slot.childNodes)        // NodeList []
console.log(slot.assignedNodes())   // Array [ #text "Custom name" ]
  • When the spec says "For each child node of the current node," does it include assigned nodes when slots are being examined?
  • Should it be updated to mention assigned nodes or am I misunderstanding the spec?

The browser implementations seem to be looking at assigned nodes as well as child nodes, so I'm wondering why the spec doesn't mention them.

@jnurthen
Copy link
Member

jnurthen commented Sep 4, 2020

This doesn't sound like something accname should be defining. This should be defined in HTML-AAM IMO

@jnurthen
Copy link
Member

jnurthen commented Sep 5, 2020

Accessible name for a button is defined at https://www.w3.org/TR/html-aam-1.0/#button-element-accessible-name-computation
As there is no aria-label or aria-labelledby on the button Accname is not involved. Hence closing this. If html-aam does not correctly answer the question then I encourage you to open an issue there.

@jnurthen jnurthen closed this as completed Sep 5, 2020
@JAWS-test
Copy link

JAWS-test commented Sep 5, 2020

@jnurthen

As there is no aria-label or aria-labelledby on the button Accname is not involved

Unfortunately I do not understand the argument. Accname is the general specification for determining names, not only in relation to aria-label and aria-labelledby. If custom elements (general, not only as buttons) are a special case concerning the determination of names, this should be considered in Accname.

I am not an expert for custom elements and so I cannot say if Accname currently describes the determination of names (and description) of custom elements correctly and completely. If this is not the case, please reopen the issue

@geoffrich
Copy link
Author

Yeah, to me this seems to be a special case not covered by the spec. I can also easily contrive an example using aria-labelledby that has the same issue.

<template id="button-template">
    <div id="label">
        <slot></slot>
    </div>
    <button aria-labelledby="label">Name 1</button>
</template>
<custom-button>Submit</custom-button>
<script>
    customElements.define(
        'custom-button',
        class extends HTMLElement {
            constructor() {
                super();
                const template = document.getElementById('button-template')
                    .content;
                const shadowRoot = this.attachShadow({ mode: 'open' }).appendChild(
                    template.cloneNode(true)
                );
            }
        }
    );
</script>

The button within the custom element is labeled by another element whose content is a slot. However, the text node "Submit" is not a child node of the element labeling the button -- it is an assigned node, a concept (I believe) unique to slots. It seems like a strict interpretation of the spec would ignore assigned nodes and thus be unable to determine the accessible name. Despite that, Chrome and Firefox both identify the name of the button to be Submit (which is the desired behavior).

If you pop open my example in a browser and open dev tools you can see the difference. The "Submit" text node is outside the slot and is not a child node.
image

Should "child nodes" be understood to include assigned nodes as well, and if so, should this be clarified in the spec?

@geoffrich
Copy link
Author

If you would prefer another example, let me know. I should be able to demonstrate this issue with any element that needs to determine an accessible name -- simply place a slot where the name should go.

@jnurthen jnurthen reopened this Sep 7, 2020
@jnurthen
Copy link
Member

jnurthen commented Sep 7, 2020

Happy to reopen now there is ARIA involved and the spec is invoked!

@jnurthen jnurthen added the Agenda label Sep 9, 2020
@geoffrich
Copy link
Author

Also note the edge case where a slot has default content. In this case, the accessible name should be based on the slot's child nodes OR the slot's assigned nodes, depending on if content is passed.

<template id="button-template">
  <div id="label">
    <slot>Default name</slot>
  </div>
  <button aria-labelledby="label">Name 1</button>
</template>
<custom-button></custom-button>
<custom-button>Custom name</custom-button>

When nothing is passed to the slot, the accessible name should be based on the default content (which is a child node)

const slot1 = document
  .querySelectorAll('custom-button')[0]
  .shadowRoot.querySelector('slot');

console.log(slot1.childNodes); // NodeList [ #text "Default name"]
console.log(slot1.assignedNodes()); // Array [  ]

When text is passed to the slot, the accessible name calculation should ignore child nodes (which still contains the default content) and use assigned nodes instead.

const slot2 = document
  .querySelectorAll('custom-button')[1]
  .shadowRoot.querySelector('slot');
console.log(slot2.childNodes); // NodeList [#text "Default name"]
console.log(slot2.assignedNodes()); // Array [ #text "Custom name" ]

As in the previous examples, browsers (at least Chrome and Firefox, not sure about Safari) are implementing this as desired. These cases simply don't seem to be considered in the spec.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants