mmag

ハマったことメモなど

slotの中身を表示するCustom Element

CSSフレームワークのドキュメントとかでよくある、ボタンが並んでて、その隣にそれらがどんなHTMLでマークアップされているか併記されてるやつをやりたくなり、ちょっと調べたら行けそうだったのでやってみた。

こう書くと

<show-content>
  <button id="inc">+1</button>
  <script>
    let count = 0

    document.querySelector('#inc').addEventListener('click', () => {
      console.log(++count)
    })
  </script>
</show-content>

こうなるような

f:id:Joe_noh:20210912170008p:plain

show-contentです。this.innerHTMLにドカッと入ってくるので、それをcode要素のinnerHTMLに与えているだけ。インデントの外し方はかなり適当。

<template id="show-content">
  <style>
    pre {
      margin: 1rem 0 0 0;
      padding: 0;
      overflow-x: scroll;
      line-height: 1.3;
    }
  </style>
  <div>
    <slot></slot>
    <pre><code id="code"></code></pre>
  </div>
</template>

<script>
  class ShowContent extends HTMLElement {
    constructor() {
      super()

      const template = document.getElementById('show-content')
      const node = template.content.cloneNode(true)

      this.attachShadow({ mode: 'open' }).appendChild(node)
    }

    connectedCallback() {
      const codeBlock = this.shadowRoot.querySelector('#code')

      codeBlock.innerText = this.removeIndent(this.innerHTML)
    }

    removeIndent(html) {
      const firstLineIndent = /^\s+/.exec(html)[0]

      return html.replaceAll(firstLineIndent, "\n").trim()
    }
  }

  customElements.define('show-content', ShowContent)
</script>