npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@mediquo/elements

v0.9.4

Published

Mediquo elements web components

Readme


Lit custom elements for scheduling, video consultations, chat, and payments. Each feature ships as its own entry point — import only what you need. Components are routing-agnostic: they emit semantic events and leave navigation to the host.

Installation

npm install @mediquo/elements

Quick start

Wrap features with the providers they need, then mount the element:

<script type="module">
  import "@mediquo/elements/mq-theme-provider";
  import "@mediquo/elements/mq-query-client-provider";
  import "@mediquo/elements/mq-schedule";
</script>

<mq-theme-provider theme="mediquo">
  <mq-query-client-provider>
    <mq-schedule
      api-key="YOUR_API_KEY"
      token="YOUR_ACCESS_TOKEN"
      locale="es_ES"
      env="production"
    ></mq-schedule>
  </mq-query-client-provider>
</mq-theme-provider>
const schedule = document.querySelector("mq-schedule");

schedule?.addEventListener("appointment-created", (event) => {
  const { appointmentId } = (event as CustomEvent).detail;
  // host decides where to go next
});

schedule?.addEventListener("back", () => {
  // user left the wizard
});

Components

| Element | Import | Description | | --- | --- | --- | | mq-dashboard | @mediquo/elements/mq-dashboard | Patient home dashboard (hero, next appointment, recent documents, support banner); emits redirect events | | mq-schedule | @mediquo/elements/mq-schedule | Multi-step appointment booking / reschedule | | mq-schedule-success | @mediquo/elements/mq-schedule-success | Post-booking confirmation screen | | mq-my-appointments | @mediquo/elements/mq-my-appointments | Upcoming and past appointments | | mq-videocall | @mediquo/elements/mq-videocall | Video consultation session | | mq-chat-room | @mediquo/elements/mq-chat-room | Chat with a professional | | mq-support-chat | @mediquo/elements/mq-support-chat | Support chat bubble | | mq-checkout | @mediquo/elements/mq-checkout | Generic payment checkout | | mq-appointment-checkout | @mediquo/elements/mq-appointment-checkout | Appointment payment | | mq-immediate-videocall-checkout | @mediquo/elements/mq-immediate-videocall-checkout | Immediate videocall payment | | mq-apple-pay-checkout | @mediquo/elements/mq-apple-pay-checkout | Apple Pay button | | mq-google-pay-checkout | @mediquo/elements/mq-google-pay-checkout | Google Pay button |

Most features accept api-key, token, locale, and env when used standalone. See the documentation for per-component attributes and events.

mq-schedule offers no digital wallet in its payment step unless the host opts in. Add google-pay-enabled or apple-pay-enabled to offer them; each still requires device support and a gateway that accepts wallets.

<mq-schedule api-key="YOUR_API_KEY" apple-pay-enabled></mq-schedule>

In React, the same flags are googlePayEnabled / applePayEnabled on MqSchedule.

Providers

Mount these as ancestors of the features that need them:

| Provider | Import | When | | --- | --- | --- | | mq-theme-provider | @mediquo/elements/mq-theme-provider | Always — design tokens | | mq-query-client-provider | @mediquo/elements/mq-query-client-provider | Data-fetching features (mq-schedule, mq-chat-room, …) | | mq-socket-provider | @mediquo/elements/mq-socket-provider | Realtime features (mq-chat-room) | | mq-session-provider | @mediquo/elements/mq-session-provider | Features that read the patient session — mq-dashboard, mq-my-appointments, mq-videocall, mq-appointment-documentation, background sync | | mq-api-client-provider | @mediquo/elements/mq-api-client-provider | Features configured entirely by context — mq-my-appointments, mq-unread-count-sync, mq-professional-presence-sync — and any subtree you want scoped to one organization |

Set mq-session-provider's session as a property (it's the login-token response object from your auth exchange, not a string attribute):

<mq-theme-provider theme="mediquo">
  <mq-query-client-provider>
    <mq-socket-provider>
      <mq-session-provider id="session">
        <!-- feature elements -->
      </mq-session-provider>
    </mq-socket-provider>
  </mq-query-client-provider>
</mq-theme-provider>

<script type="module">
  document.querySelector("#session").session = loginTokenResponse;
</script>

In React, pass it as a prop: <MqSessionProvider session={loginTokenResponse}>.

Organizations

api-key identifies the organization an element speaks for. Each element builds its own API client from the api-key it was given and keeps it for its whole lifetime, so requests always carry the key that element was configured with — whatever other elements mount, update or unmount alongside it.

Cached data is scoped by that key too. Two organizations never read each other's cache, and changing an element's api-key in place shows the new organization's data, not the previous one's.

Several organizations on one page

Supported, with no extra setup. Give each element its own api-key:

<mq-query-client-provider>
  <!-- clinic booking -->
  <mq-schedule api-key="CLINIC_KEY" token="..."></mq-schedule>

  <!-- your tenant's support chat, at the same time -->
  <mq-support-chat api-key="TENANT_KEY" token="..."></mq-support-chat>
</mq-query-client-provider>

One mq-query-client-provider for the whole session is fine — the cache is partitioned by organization inside it. You do not need to remount it, clear the cache, or key elements by organization.

Elements without an api-key

Upgrading: mq-my-appointments, mq-unread-count-sync and mq-professional-presence-sync used to inherit whatever organization the last element on the page happened to configure. That is what made two organizations unsafe. Wrap them in mq-api-client-provider — it is the only integration change this release asks for.

Some features take no api-key of their own (mq-my-appointments, mq-unread-count-sync, mq-professional-presence-sync), and some accept one but are often embedded (mq-chat-room). Wrap those in mq-api-client-provider to say which organization the subtree belongs to:

<mq-api-client-provider api-key="CLINIC_KEY" token="...">
  <mq-my-appointments></mq-my-appointments>
</mq-api-client-provider>

An element inside a provider that is given its own api-key uses its own; one given only a token binds that token to the organization it inherited. Mount one provider per organization — they nest and coexist.

Background sync

Two headless elements keep the shared query cache in sync with realtime socket events, so unread badges and presence indicators update without refetching. Mount each once, under the query-client + socket providers and inside the mq-api-client-provider for the organization whose data they keep fresh; they render nothing:

| Element | Import | Keeps in sync | | --- | --- | --- | | mq-unread-count-sync | @mediquo/elements/mq-unread-count-sync | Per-room unread counts (incoming messages) | | mq-professional-presence-sync | @mediquo/elements/mq-professional-presence-sync | Professional active_absence (presence) |

<mq-query-client-provider>
  <mq-socket-provider>
    <mq-api-client-provider api-key="YOUR_API_KEY" token="...">
      <mq-unread-count-sync></mq-unread-count-sync>
      <mq-professional-presence-sync></mq-professional-presence-sync>
      <!-- feature elements whose cached data these keep fresh -->
    </mq-api-client-provider>
  </mq-socket-provider>
</mq-query-client-provider>

For a Lit host that prefers wiring the logic into its own element, the UnreadCountSyncController / ProfessionalPresenceSyncController reactive controllers are exported from the same subpaths.

Toasts

Mount one <mq-toast-container> and drive it imperatively with registerToastContainer:

import { registerToastContainer, toast } from "@mediquo/elements/toast";

// Point the toast API at a container that inherits your theme/token context:
registerToastContainer(document.querySelector("mq-toast-container"));

toast.success("Saved");
toast.error("Something went wrong");

Theming

mq-theme-provider ships two built-in themes: default and mediquo. Override tokens with custom-tokens, or build a typed theme via @mediquo/elements/theme:

<mq-theme-provider
  theme="custom"
  custom-tokens="--color-primary: #0b6e4f; --color-background: #f7faf8;"
>
  <!-- … -->
</mq-theme-provider>
import { createTheme } from "@mediquo/elements/theme";

const theme = createTheme({
  "--color-primary": "#0b6e4f",
});

Brand themes (e.g. Adeslas) via custom-tokens

@mediquo/elements intentionally ships only the design-system-owned themes (default, mediquo). Partner brands such as Adeslas are not built into the package — the host owns the brand and supplies it through custom-tokens.

custom-tokens is raw CSS injected into the provider's shadow root after the selected theme, so it can override any token the design system exposes. There is no token a built-in theme can set that custom-tokens cannot — the surface is complete by construction. Pass the brand's token set as a :host { … }-free list of custom properties:

<mq-theme-provider
  theme="default"
  custom-tokens="
    --color-primary: #6f2c91;
    --color-primary-hover: #5a2475;
    --font-titles: 'Adeslas', sans-serif;
    /* …the rest of the brand's token overrides… */
  "
>
  <!-- … -->
</mq-theme-provider>

Keep the brand's token values in the host application (or a shared host package), not in @mediquo/elements. This keeps the published package brand-neutral while letting integrators render any look on top of it.

Icons

Every icon this package renders is drawn in this repository, on a single 24 grid at the design system's icon stroke, and inherits currentColor. The only artwork we do not draw is the Google Pay and Apple Pay brand marks, which their owners require us to display unmodified.

See src/ui/icons/ICONS.md for the full inventory and the rules for adding a new icon.

Events

Components describe what the user did, never where to navigate. Listen for the actions you care about and own routing in the host.

Shared contract (also exported from @mediquo/elements/events):

| Event | Detail | Meaning | | --- | --- | --- | | mq-back | { source?: string } | Generic back chrome | | mq-home | — | Go to home | | mq-view-appointments | { tab: "next" \| "history" } | Open appointments list | | mq-appointment-book | { specialty?, service?, professional? } | Start booking | | mq-appointment-reschedule | { appointmentId } | Reschedule | | mq-appointment-join-videocall | { appointmentId } | Join videocall | | mq-appointment-view-documentation | { appointmentId } | Open documentation | | mq-view-documents | — | Open the full documents list (from mq-dashboard) | | mq-download-file | { url, filename } | Host should persist / download a file |

mq-download-file is emitted by mq-chat-room and also bubbles from mq-support-chat (nested room). Feature-specific events (e.g. appointment-created on mq-schedule) are documented per component.

import { DownloadFileEvent } from "@mediquo/elements/events";

el.addEventListener(DownloadFileEvent.eventName, (event) => {
  const { url, filename } = event.detail;
  // save or trigger a download
});

In React, the same callback is onDownloadFile on MqChatRoom and MqSupportChat:

import { MqSupportChat } from "@mediquo/elements/react/mq-support-chat";

<MqSupportChat
  apiKey="TENANT_KEY"
  token="..."
  onDownloadFile={(event) => {
    const { url, filename } = event.detail;
    // save or trigger a download
  }}
/>

Locale and environment

Supported locales: es_ES, en_US, pt_PT, de_DE, ca_ES.

Pass locale as an attribute on the feature element, or call setLocale from @mediquo/elements/i18n.

For non-production backends:

import { setEnv } from "@mediquo/elements/env";

setEnv("development"); // or "production"

You can also set env="development" / env="production" on elements that expose it.

TypeScript

Entry points ship with .d.ts files. For modern package exports, prefer:

{
  "compilerOptions": {
    "moduleResolution": "bundler",
    "module": "ESNext"
  }
}

Custom elements work in any framework that can render HTML. In React / Next.js, dynamic-import the entry points in a client component and attach listeners with addEventListener.

License

ISC