Use MatterViz on non‑Svelte sites

Preferred: Web Components (Custom Elements)

You can compile Svelte components to custom elements and consume them anywhere (React, Vue, plain HTML) via shadow DOM. This is framework‑agnostic.

Minimal custom element StructureCE.svelte for Structure.svelte:

<!-- matterviz/structure/StructureCE.svelte -->
<script>
  import { Structure } from 'matterviz'
  let props = $props()
</script>

<svelte:options customElement="mv-structure" />

<Structure {...props} />

Use in React (set properties and callbacks via ref):

import { useEffect, useRef } from 'react'
// Ensure `mv-structure` custom element is defined in browser
import 'matterviz/structure/StructureCE.svelte'

export default function StructureEmbed() {
  const ref = useRef(null)

  useEffect(() => {
    const el = ref.current as unknown as
      | HTMLElement & {
        data_url?: string
        show_controls?: boolean | number
        performance_mode?: 'quality' | 'speed'
        on_file_load?: (data: unknown) => void
      }
      | null
    if (!el) return
    el.data_url = '/TiO2.cif'
    el.show_controls = true
    el.performance_mode = 'quality'
    el.on_file_load = (data) => {
      // handle callback data
    }
    return () => { // return a cleanup function to remove event handlers
      if (el) el.on_file_load = undefined
    }
  }, [])

  return <mv-structure ref={ref} />
}

Use in Vue (set properties and callbacks via ref):


  <mv-structure ref="mv" />

<script setup>
import { onBeforeUnmount, onMounted, ref } from 'vue'
const mv = ref()
onMounted(() => {
  if (!mv.value) return
  mv.value.data_url = '/TiO2.cif'
  mv.value.show_controls = true
  mv.value.performance_mode = 'quality'
  mv.value.on_file_load = (data) => {
    // handle callback data
  }
})
onBeforeUnmount(() => {
  if (mv.value) mv.value.on_file_load = undefined
})
</script>

Notes

<iframe> (future option)

We may expose iframe embeds for some demos in the future, but this path is currently not supported. Prefer the custom‑elements approach above. Reasons favoring <iframe>: