Closed jcfranco closed 1 year ago
@jcfranco that utility assumes that the component is wrapped by a label or the component itself has aria-labeledby. I'm not sure that would work for a lot of the components.
It may work for some of the input/control components that we expect are wrapped by a calcite-label.
The util also tries to find an associated label (using for
). We can use it as a base and extend it to include calcite-label
and aria-label
in that algorithm. This logic would work for any component, IMO.
Yes, but it means instead of just setting a label on a component the user has to create a calcite-label or label element somewhere.
The user can set aria-label
on the component itself.
Assuming we support the pattern of setting aria-label
directly on calcite form components, even with an automated system that also assigns an aria-label on internal elements inside the shadowRoot of said form components (to get a11y tests to pass), wouldn't that result in duplicate aria-label
's being set, because you would have one on the custom element and the same one on the <input>
inside the custom element's shadowRoot?
What's confusing to me is that when we make a shadowed component that renders an <input>
in its shadowRoot, browsers, screen readers and a11y tests expect that shadowed <input>
to be properly labeled even though the custom host element has an aria-label
on it, or is wrapped in a label or calcite-label.
It almost feels like the cleanest solution is to not use <input>
tags inside shadowRoots, but still allow typing or input, but that opens up a huge can of reinventing the wheel of basic input behaviors.
What's confusing to me is that when we make a shadowed component that renders an in its shadowRoot, browsers, screen readers and a11y tests expect that shadowed to be properly labeled even though the custom host element has an aria-label on it, or is wrapped in a label or calcite-label.
It may be a problem that the input and label are across shadow boundaries. I think they have to be within the same root node. I'm not 100% sure though. If that is the case, we may need to have both the native input and label slotted in order to keep them in the same root node and still allow styling to them.
Assuming we support the pattern of setting aria-label directly on calcite form components, even with an automated system that also assigns an aria-label on internal elements inside the shadowRoot of said form components (to get a11y tests to pass), wouldn't that result in duplicate aria-label's being set, because you would have one on the custom element and the same one on the inside the custom element's shadowRoot?
Yes it would duplicate unless we removed it on the host (which seems like a bad practice).
It may be a problem that the input and label are across shadow boundaries. I think they have to be within the same root node.
This is definitely true in the context of using native browser behavior for both form accessibility and native form behavior.
The problem is we're making custom elements that compose native form elements (either inside or outside a shadowRoot) without a browser API for taking control of native form behavior, which puts us in an awkward position of trying to both take advantage of native form behavior but also allowing consumers of our custom elements to set "native" properties like aria-label
on them and expect it to work just like the native equivalent.
What we really need the ability to do is extend native components like input and label, but the browser support for that isn't there.
What we really need the ability to do is extend native components like input and label, but the browser support for that isn't there.
Yes that might solve the problems.
The problem is we're making custom elements that compose native form elements (either inside or outside a shadowRoot) without a browser API for taking control of native form behavior
But if we made our <calcite-input>
have a required slot for a native input element, we could wrap and style the native input as well as keep support native form behavior.
We could do the same with <calcite-label>
and require a slot for a native label element.
I think the above would be better than creating the native input inside of shadowRoot or creating the label ourselves inside light dom (which gives us problems in frameworks)
But if we made our
have a required slot for a native input element, we could wrap and style the native input as well as keep support native form behavior.
Converting calcite-input
to scoped
would accomplish essentially the same thing without the user having to provide the native input.
We could do the same with
and require a slot for a native label element.
If we decide to stick with using scoped components, there would be no need to do this since calcite-label
already exposes its internal label
.
A third option we could explore would be to completely ditch using <input>
and <label>
and instead just use ARIA roles on generic divs: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/textbox_role
<div role="textbox" contenteditable="true"></div>
This method (in theory) would allow assistive technologies to still work without the complexity of having to manage native inputs and labels, but the major drawback would be the burden of supporting all the behavior those components provide without actually using them. It could be worth it though since it would give us 100% control over every way that the component is supposed to work.
Converting calcite-input to scoped would accomplish essentially the same thing without the user having to provide the native input.
I think the scoped components have issues of their own and it sounds like Stencil might be moving away from them. IMO its better to have a shadowed component that can separate its internals from being exposed.
A third option we could explore would be to completely ditch using and
I don't think this would work unless both the label div and input div are in the same shadowRoot. It faces the same issue as this: It may be a problem that the input and label are across shadow boundaries. I think they have to be within the same root node.
I don't think this would work unless both the label div and input div are in the same shadowRoot.
We could try setting the role and contenteditable
on the Host element, that way the editable div isn't inside a shadowRoot.
yeah that might work. I'm not sure a native form would pick it up based on the role though.
Would be a good research project @eriklharper
yeah that might work. I'm not sure a native form would pick it up based on the role though.
Right, we would have to implement our own form component in that case, most likely.
Another possibility down the road is we can support native forms with separate native-supported components, similarly to the calcite-select
which was intentionally made to support the browser-native select dropdown UI. That way people have a choice whether they need native form support or not.
Would be a good research project @eriklharper
There's even a form
role, go figure. https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/Form_Role
sounds like Stencil might be moving away from them
@driskull where did you hear this?
It makes sense because per spec slots are for shadow components. We should probably move away from scoped components and have all shadowed ones.
If we implement our own form with role then we will have to implement all the logic that native forms do. It's doable but it duplicates a lot of work that the browser handles already.
IMO I think that slotting inputs, textareas, labels would make it simpler to maintain native support for forms and forms within frameworks as well as get rid of some duplicate props that we have on input components just to pass them to the native input.
Looks like I need an Ionic account to login to that. Could you snip out the part that's relevant perhaps?
As per scoped versus shadow, I think ultimately shadow is better otherwise what's the point of making encapsulated styles? But I also am unsure if shadow is the end-all-be-all particularly as it relates to form stuff. If we really adopt a model where people are expected to slot-in native form elements, I just feel like the only thing that they really gain is just the brand styling? But even then, the styling is not encapsulated, so I don't ultimately see the value with that approach.
Unless I'm misunderstanding if slotted inputs and labels can still participate inside a <form>
. Have you verified that a parent <form>
detects slotted inputs?
I just feel like the only thing that they really gain is just the brand styling?
Yeah I think so. I think that is the point though right? We can style the native form elements and offer some stuff on top of them without having just a CSS library that requires they add a class on the native element.
But even then, the styling is not encapsulated, so I don't ultimately see the value with that approach.
The styling is still encapsulated in the shadow dom I think, right? The slotted styles would be untouchable to the end user.
Unless I'm misunderstanding if slotted inputs and labels can still participate inside a form. Have you verified that a parent
I don't see why they wouldn't as they are still just within the light dom.
We can style the native form elements and offer some stuff on top of them without having just a CSS library that requires they add a class on the native element.
Except that the styling is unrestricted because its not inside a shadowRoot, which is one of the central tenets of the library is enforcing brand consistency. I need to test this though.
Yeah, that's one of the cons to using slots, they are still in light dom so they can be styled with. I'm sure we could control most of it though.
Closing this issue as it won't be applicable to all components.
The original idea would only work if there's a single element to be labeled within the component. This falls apart with more complex components where props are needed to label different internal elements (e.g., slider
's maxLabel
, minLabel
props). cc @geospatialem
Background
Some of our components have a
label
property solely to assign a11y labels on the host or internal components. I think we can simplify this by enhancing our components to look up this info without relying on a custom prop.Ionic Framework has a util for looking up the ARIA label: https://github.com/ionic-team/ionic-framework/blob/master/core/src/utils/helpers.ts#L127-L140. Maybe we can adopt something similar and drop the
label
prop.We could tackle this in two phases:
cc @driskull @eriklharper
Desired Outcome
Introduce a utility for components to look up appropriate labels (for a11y) and no longer rely on
label
.