SolidJSS
SolidJSโ€ข3mo agoโ€ข
12 replies
hyperknot

How to interact with innerHTML

I'm trying to solve the following. I get sanitised HTML string from my Markdown renderer.
I put use it in an innerHTML.
I'd like to parse it, recognise the code blocks and add a "Copy to clipboard" button to each code block (top and bottom corners).

This is the best code I could come up.
Since I never used createRoot, getOwner or insert before, I'd like to ask if this is the correct usage or not.

The alternative would have been to render, but I think createRoot is faster, right?

import { CopyButton } from '@shared/components/ui/CopyButton'
import { base64ToUtf8 } from '@shared/lib/utils'
import { type Component, createRoot, getOwner, onCleanup, onMount } from 'solid-js'
import { insert } from 'solid-js/web'

export const AssistantMessage: Component<{
  message: string
}> = (props) => {
  let contentRef!: HTMLDivElement
  const disposers: Array<() => void> = []

  const getHTML = () => {
    return props.message
  }

  onMount(() => {
    if (!contentRef) return

    const owner = getOwner() 

    const codeBlocks = contentRef.querySelectorAll('.code-block-container')

    codeBlocks.forEach((block) => {
      const encoded = block.getAttribute('data-code')
      if (!encoded) return

      const code = base64ToUtf8(encoded)

      const topContainer = document.createElement('div')
      const bottomContainer = document.createElement('div')

      block.prepend(topContainer)
      block.append(bottomContainer)

      createRoot((dispose) => {
        insert(topContainer, () => <CopyButton code={code} position="top" />)
        disposers.push(dispose)
      }, owner)

      createRoot((dispose) => {
        insert(bottomContainer, () => <CopyButton code={code} position="bottom" />)
        disposers.push(dispose)
      }, owner)
    })
  })

  onCleanup(() => {
    disposers.forEach((d) => {
      d()
    })
  })

  return (
    <div>
      <div ref={contentRef} innerHTML={getHTML()} />
    </div>
  )
}
Was this page helpful?