Building blocksInstallFramework guides

Vue 3

Use the CDN bundle with Vue 3 script setup.

src/components/MedosBooking.vue
<script setup lang="ts">
import { onBeforeUnmount, onMounted } from "vue";

const CDN_URL = "https://widgets.medos.one/v2/unified.js";
const CONTAINER_ID = "medos-booking-vue";

type MedosBookingApi = {
  init: (config: Record<string, unknown>) => void;
  open: (config?: Record<string, unknown>) => void;
  close: () => void;
};

const props = defineProps<{ apiKey: string }>();

const medos = () =>
  (window as unknown as { MedosBooking?: MedosBookingApi }).MedosBooking;

/** Reuses an existing tag, so remounting doesn't re-download the bundle. */
function load(): Promise<void> {
  if (medos()) return Promise.resolve();

  const existing = document.querySelector<HTMLScriptElement>(
    `script[src="${CDN_URL}"]`,
  );
  if (existing) {
    return new Promise((resolve) =>
      existing.addEventListener("load", () => resolve(), { once: true }),
    );
  }

  return new Promise((resolve, reject) => {
    const script = document.createElement("script");
    script.src = CDN_URL;
    script.async = true;
    script.onload = () => resolve();
    script.onerror = () => reject(new Error("Medos Booking failed to load"));
    document.head.appendChild(script);
  });
}

let cancelled = false;

onMounted(async () => {
  try {
    await load();
    if (cancelled) return;
    medos()?.init({
      apiKey: props.apiKey,
      mode: "inline",
      containerId: CONTAINER_ID,
    });
  } catch (err) {
    console.error(err);
  }
});

onBeforeUnmount(() => {
  cancelled = true;
  // Inline mode has no close() — clear the container so a remount doesn't
  // stack a second widget.
  const el = document.getElementById(CONTAINER_ID);
  if (el) el.innerHTML = "";
});
</script>

<template>
  <div :id="CONTAINER_ID" style="min-height: 600px" />
</template>

Use the component:

<MedosBooking api-key="mk_your_publishable_key" />

Initialize once with mode: "modal" and no containerId, then open from any button. Guard the call in case the bundle hasn't loaded yet:

<button @click="() => (window as any).MedosBooking?.open()">
  Book appointment
</button>

On this page