Custom audio kirbytag; how to make HTML tag self-closing?

I’m creating a custom kirbytag for the audio element; I’ve modified the code for the files kirbytag like so:

Kirby::plugin('minttoothpick/audio-kirbytag', [
  'tags' => [
    'audio' => [
      'attr' => [
      'html' => function ($tag) {
        if (!$file = $tag->file($tag->value)) {
          return $tag->text;
        $source = Html::tag('source', null, [
          'src'      => $file->url(),
          'type'     => $file->mime(),
        return Html::tag('audio', [$source, 'Your browser does not support the audio tag.'], [
          'controls' => $tag->controls !== 'false',
          'class'    => $tag->class,

Everything seems to be working, except when I nest the <source> ($source) tag in the returned <audio> (Html::tag()) tag, it’s not self-closing… instead, it wraps the fallback text inside of the <source>:

<audio controls>
  <source src="url/to/my.mp3" type="audio/mpeg">
  Your browser does not support the audio tag.

I see in the docs for Html::tag() that if parameter 2 is set to null it should generate a self-closing tag… anyone have some advice?

Which browser are you using? I tested your tag in Safari without your issue.

If you only have a single source, you don’t even need the source tag:

When I view source in Chrome or Firefox, the fallback text is indeed wrapped in the <source> tag, but when using the web developer inspector in either browser, it seems that they interpret things correctly, and the closing </source> does not appear. It leads me to believe that the actual code output is printing the closing tag, but that the browsers are removing it from their display.

I was considering the single-source option (just putting src='...' on the <audio> tag itself), but eventually I’d like to extend my code to work with multiple audio file formats/sources for browser compatibility.

If the Html::tag() stuff doesn’t work for you, you can use a snippet instead. Just keep in mind that there is currently anissue with empty lines and indents in snippets. But apart from that it might be a better alternative, especially if markup becomes more complex.