Skip to content

a11y: los componentes que dependen de un label opcional pueden quedar sin nombre accesible #47

Description

@Zenemig

El problema

Varios componentes exponen el nombre accesible como una prop label opcional. Si
quien consume el componente no la pasa, el elemento queda sin nombre accesible
y no hay nada en la librería que lo advierta: no falla el build, no falla el lint y
no falla ningún test.

Los casos que encontramos hasta ahora:

  • ch-modal — un diálogo modal sin label se anuncia solo como «diálogo». Es
    el caso más grave, porque un modal siempre necesita nombre y, como el encabezado
    va en un slot en el light DOM, no se puede referenciar con aria-labelledby a
    través del shadow boundary. No existe un valor por defecto razonable.
  • ch-button — un botón de solo icono sin label queda sin nombre.
  • ch-spinner — sin label queda decorativo (aria-hidden), lo que acá sí es
    intencional y correcto.

O sea: el mismo patrón («label opcional») significa cosas distintas según el
componente. En ch-spinner la ausencia es una decisión válida; en ch-modal y en
un ch-button de solo icono es un bug de accesibilidad silencioso.

Por qué conviene resolverlo a nivel de librería

Hoy los 16 componentes declaran label?: string. No hay ninguna prop obligatoria
en la librería y tampoco hay precedente de console.warn en ningún componente. Por
eso preferimos no inventar un mecanismo nuevo en un solo componente: quedaría
inconsistente con los otros 15 y el próximo componente repetiría el problema.

La decisión que hay que tomar es transversal, no de ch-modal.

Opciones a discutir

  1. Prop obligatoria en el tipo — declarar @Prop() label!: string en los
    componentes donde la ausencia nunca es válida. Da error de compilación a quien
    consume desde TypeScript/JSX, pero no protege a quien usa HTML directo.
  2. Advertencia en desarrollo — un console.warn cuando falta el nombre. Avisa
    en todos los casos, incluido HTML directo, pero es un patrón nuevo para la
    librería y hay que definir dónde vive para no repetirlo en cada componente.
  3. Convención documentada solamente — dejarlo en docs/components.md y en el
    JSDoc de cada prop. Es lo que hay hoy; no evita el error.
  4. Una mezcla — tipo obligatorio donde se pueda, más una advertencia
    compartida para el resto.

También hay que decidir qué hacer con el caso «el label y el encabezado del slot
pueden decir cosas distintas», que hoy nada mantiene sincronizado.

Estado

Lo dejamos como discussion porque la respuesta define una convención para toda la
librería y conviene acordarla antes de tocar 16 componentes. Salió de la revisión de
#20; ahí ch-modal quedó con
label opcional para no divergir del resto, y documentado en docs/components.md
como una prop que hay que pasar siempre.

Metadata

Metadata

Assignees

No one assigned

    Labels

    discussionIdea en discusión — todavía no está lista para tomarenhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions