Adding attributes to Image Figure elements from Kirbytext

I’m trying to sort out how to modify how images are rendered via Kirbytext – in particular, how to add an attribute to the <figure> element that wrap images.

I’d like to add the role="group" attribute across the board as this is good practice for accessibility reasons. I’ve been digging through the cookbook recipe on reusing KirbyTags in custom tags but am totally stuck at how to adjust the HTML output for this.

Appreciate any pointers/help — thanks!

1 Like

You can override the original tag and re-create the property, basically copy and paste everything from the original image tag and change the html to your liking.

1 Like

I thought I had figured out what you were getting at, but nothing has worked so far. The main change is the return statement at the end to change the HTML output which still needs work on its own, but for now I just want to be sure I can get this to output something at all.

<?php
Kirby::plugin('scottboms/kirby3-aria-figure', [
  'tags' => [
    /**
     * Redefined standard Image tag from
     * kirby/config/tags.php
     */
    'image' => [
      'attr' => [
        'alt',
        'caption',
        'class',
        'height',
        'imgclass',
        'link',
        'linkclass',
        'rel',
        'target',
        'title',
        'width',
        'role' // new role attribute
      ],
      'html' => function ($tag) {
        if ($tag->file = $tag->file($tag->value)) {
          $tag->src     = $tag->file->url();
          $tag->alt     = $tag->alt     ?? $tag->file->alt()->or(' ')->value();
          $tag->title   = $tag->title   ?? $tag->file->title()->value();
          $tag->caption = $tag->caption ?? $tag->file->caption()->value();
          $tag->role    = $tag->role->value();
        } else {
          $tag->src = Url::to($tag->value);
        }

        $link = function ($img) use ($tag) {
          if (empty($tag->link) === true) {
            return $img;
          }

          if ($link = $tag->file($tag->link)) {
            $link = $link->url();
          } else {
            $link = $tag->link === 'self' ? $tag->src : $tag->link;
          }

          return Html::a($link, [$img], [
            'rel'    => $tag->rel,
            'class'  => $tag->linkclass,
            'target' => $tag->target
          ]);
        };

        $image = Html::img($tag->src, [
          'width'  => $tag->width,
          'height' => $tag->height,
          'class'  => $tag->imgclass,
          'title'  => $tag->title,
          'alt'    => $tag->alt ?? ' '
        ]);

        if ($tag->kirby()->option('kirbytext.image.figure', true) === false) {
          return $link($image);
        }

        // render KirbyText in caption
        if ($tag->caption) {
          $tag->caption = [$tag->kirby()->kirbytext($tag->caption, [], true)];
        }

        return '<figure role="' . $tag->role . '" class="' . $tag->class .'">' . $link($image) . '<figcaption>' . $tag->caption . '</figcaption></figure>';

      }
    ]

  ]
]);

The problem is that you use multiple return statements. Keep in mind that a strict exits as soon as it hits a return statement.

https://www.php.net/manual/en/function.return.php

Thanks Sonja — after a bit more debugging, I realized that this plugin was being overridden by another because of the order they were loading. Once I solved that, the rest proved to be quite simple to do thanks to your suggestions. I’ll tidy up the code a bit more and share where I ended up.

Out of interest: Do you have a source for this requirement?

The only source I found was this: https://www.w3.org/WAI/tutorials/images/groups/#a-collection-of-images

But it relates to a group of images within a figure tag, not a single image.

I came across this via the a11y.css tool for checking site accessibility though you may be right and this might not be the right approach, or at least I’m going to do a bit more digging through the intent of these ARIA roles.

Uuh, an #a11y rabbit hole to dig into - sign me up! :heart_eyes_cat: I too use a11y.css for validation and have been wondering about this notification.

From what I have researched, this is to support browser-screenreader pairings that do not recognize the semantic meaning of <figure> (which has an implicit ARIA role of figure, so it seems redundant). I could not find a “requirement” source, but this is being recommended in the WAI Web Accessibility Tutorial on “Complex Images”:

The HTML5 <figure> and <figcaption> elements can be used to group image and link semantically. Adding role="group" to the figure maintains backward compatibility with web browsers that don’t support the native semantics of the <figure> element.

Yet, Scott O’Hara has an extensive article about how different screen reader setups consume <figure> tags, and he suggests:

<figure role="figure" aria-label="repeat figcaption content here">
  <!-- figure content. if an image, provide alt text -->
  <figcaption>
    Caption for the figure.
  </figcaption>
</figure>

This is to support AT setups with IE11 as well as VoiceOver and Chrome. Now, which recommendation to follow? Two trustworthy sources recommending two different best practices confuses me. But I do understand the a11y.css warning better, now.

Here is how WAI-ARIA defines group as used in the WAI Tutorial…

A set of user interface objects which are not intended to be included in a page summary or table of contents by assistive technologies.

…vs. how figure is defined, as suggested in Scott O’Hara’s recommendation:

A perceivable section of content that typically contains a graphical document, images, code snippets, or example text. The parts of a figure MAY be user-navigable.

Personally, I’m leaning towards role="figure", as that is the implicit role of <figure> and role="group" would override that with a different semantic. And there is an open Github issue on the WAI Tutorial page supporting that view (apparently role="figure" was not available when the tutorial page was first authored).

2 Likes

Thanks for adding your findings, @sebastiangreger!

Thanks for sharing all of that @sebastiangreger. All the documentation I’ve read feels sufficiently vague at best though I suppose much of that is due to inconsistent support of features across browsers and screen readers alike.