DALAT

#Niveles de encabezados en componentes reutilizables Autora Original: Suzanne Aitchison

Traducción: Mariela Lincoman, Ana Melisa Soria y Florencia Olcese.

Post original: Reusable Components With Headers

Para desarrolladores que quieran:

  • Sacar el mayor provecho de sus componentes reutilizables de React sin comprometer la accesibilidad
  • Asegurarse de que el contenido esté estructurado de forma clara
  • Aprender a crear elementos DOM de forma dinámica en React

Una de las razones clave por las que React es tan popular es la capacidad para definir un componente, pasarle algunos props y luego volver a usarlo en varios lugares, sin tener que duplicar el HTML en toda la aplicación. Al momento de crear un componente reutilizable, hay que tener en cuenta algunas cosas, por ejemplo, lo que se podría personalizar a través de props, y lo que sería una parte integral del componente en sí.

El problema con los niveles de encabezados fijo

Mirá esta versión breve del componente TopicCard que se usa en la lista de temas de este sitio y en el tema de cada página de temas:

render() {
    const { title, description, linkUrl, linkAriaLabel } = this.props;
    return (
      <div className='topic-container'>
        <div className='topic-info-wrapper'>
          <h2>{título}</h2>
          <p>{descripción}</p>
        </div>
        {!linkUrl ? null : (
          <div className='link-wrapper'>
            <Link to={linkUrl} aria-label={linkAriaLabel}>
              Ver tema
            </Link>
          </div>
        )}
      </div>
    );
  } 

ver original TopicCard.jsx alojado con ❤ en GitHub

Cómo ponerle título a tus páginas

Esta versión del componente TopicCard admite los siguientes props:

  • El título de la tarjeta que se va a mostrar
  • El contenido de la descripción que se va a mostrar
  • Las propiedades de enlace que pueden estar visibles u ocultas según se especifique o no el enlace

A primera vista, tenemos un buen componente reutilizable que podés empezar a usar en toda la aplicación. Sin embargo, tenemos un problema: el elemento "h2". Como ya hablamos en Accessibility 101, los niveles de encabezado en HTML no tienen que ver solo con el tamaño y el estilo del texto del encabezado, sino que proporcionan información semántica sobre la organización y la importancia de su contenido. Los niveles de encabezado siempre deben aumentar en un orden lógico y de a un paso a la vez.

La versión de TopicCard que mostramos antes define un elemento h2 que va a aparecer siempre que se reutilice este componente. Esto significa que solo puede usarse en una página donde ya haya un título “h1”, y donde un “h2” tenga sentido lógico para el flujo de la página. Ya que el poder de React es la reutilización flexible de componentes, podría ser beneficioso hacer algunas refactorizaciones.

Pasar un nivel de encabezado como props

El problema se puede resolver con un pequeño truco con el que podés establecer de forma dinámica el nivel de encabezado de acuerdo con los props que se pasaron. Esta es la versión actualizada de la TopicCard:

  render() {
    const {
      title,
      description,
      linkUrl,
      linkAriaLabel,
      headingLevel
    } = this.props;
    const Title = headingLevel;
    return (
      <div className='topic-container'>
        <div className='topic-info-wrapper'>
          <Title>{titulo}</Title>
          <p>{descripción}</p>
        </div>
        {!linkUrl ? null : (
          <div className='link-wrapper'>
            <Link to={linkUrl} aria-label={linkAriaLabel}>
              Ver tema
            </Link>
          </div>
        )}
      </div>
    );
  } 

ver original TopicCard_upgraded.jsx alojado con ❤ en GitHub

Como podés ver, ahora el componente admite el nivel de encabezado (por ejemplo, “h1”) como props y crea de manera dinámica el elemento de encabezado correcto que se renderiza en la TopicCard. Fijate que en el ejemplo anterior “Title” está en mayúsculas. Esto es esencial porque, de lo contrario, React no lo va a reconocer como un elemento DOM.

Ajustes y consideraciones finales

Si bien es muy eficaz crear de forma dinámica elementos DOM basados en props como éste, también podría generar un comportamiento no deseado si no se pasan los tipos de props previstos. También es recomendable asegurarse de realizar algún tipo de validación de props antes de intentar crear el elemento Título cuando se usa este enfoque. Hay muchas formas de lograr esto, pero una pequeña puesta en práctica podría ser:

render() {
    const {
      title,
      description,
      linkUrl,
      linkAriaLabel,
      headingLevel
    } = this.props;

    const validHeadingLevels = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'];

    const safeHeading = headingLevel ? headingLevel.toLowerCase() : '';

    const Title = validHeadingLevels.includes(safeHeading) ? safeHeading : 'p';

    return (
      <div className='topic-container'>
        <div className='topic-info-wrapper'>
          <Title>{título}</Title>
          <p>{descripción}</p>
        </div>
        {!linkUrl ? null : (
          <div className='link-wrapper'>
            <Link to={linkUrl} aria-label={linkAriaLabel}>
              Ver tema
            </Link>
          </div>
        )}
      </div>
    );
  }

ver original topiccard_validated.jsx.jsx alojado con ❤ en GitHub

Pero, si no se pasa un nivel de encabezado apropiado en los props, por defecto creamos un elemento de párrafo básico. ¡Excelente! Ahora se puede usar el TopicCard como elemento de la lista usando "h2" o como encabezado de la página usando "h1".

Lectura relacionada