Median

Components

Pick a component, install the package, and find every export of @mediansh/widget.

Updated Oct 1, 20263 minute read

Install

@mediansh/widget
import "@mediansh/widget/styles.css";

Import the stylesheet once. The peer dependencies are react and react-dom 18 or 19, and convex 1.25 or newer below 2. The package is marked "use client", so a Next.js server component can render it directly. Keys, environment variables and CSP are on Install the widget.

Which component

ComponentRendersResults go toWithout React
MedianSupportA launcher in the corner that opens a chat panelA conversation in InboxmountMedianSupport()
MedianSupportModalThe same launcher, with the panel centered over the pageA conversation in InboxmountMedianSupportModal()
MedianContactFormA form on your page with email, message and your own fieldsInbox. It joins the visitor's open conversation, or starts onemountMedianContactForm()
MedianFeedbackA note box that opens from your own trigger or from codeSignal, filed as a bug or a suggestionmountMedianFeedback()

Mount functions take the component's props as one object, plus a target for the contact form. See Without React.

Keys

Every component takes one of two props.

PropValueUse it when
apiKeyThe median_pk_ id from publicKeyFromMedianKey(MEDIAN_KEY)Visitors are anonymous, or you pass user yourself
identityThe path of a route built with medianIdentityYour session lives on the server. The route returns the key and the signed in user

Pass both to render on apiKey at once and pick up the user when the route answers. With neither, the component prints an error. See Identity.

Shared rules

  • Mount one support panel per page, MedianSupport or MedianSupportModal. Two share one open state and open together.
  • Mount one MedianFeedback per page, for the same reason. Its open state is separate from the support panel's.
  • Components with the same key share one visitor. A chat message, a contact form send and a feedback note from one browser belong to the same customer. The browser keeps that visitor in localStorage.
  • An error inside a component hides that component and prints to the console. Your page keeps running.
  • Component text is in English, with no locale prop. The agent's reply language is on Built-in abilities.
  • Colors come from your page's CSS variables. See Theming.

Exports

ExportKindDocumented on
MedianSupportComponentSupport widget
MedianSupportModalComponentSupport modal
MedianContactFormComponentContact form
MedianFeedbackComponentFeedback panel
mountMedianSupport, mountMedianSupportModal, mountMedianContactForm, mountMedianFeedbackFunctionWithout React
medianSupport, medianFeedbackObjectControl from code
useMedianSupport, useMedianFeedbackHookControl from code
useMedianContactHookContact form
sendMedianContactFunctionContact form
reportErrorFunctionCrash reports
useCanReportErrorHookCrash reports
TypeDocumented on
MedianSupportProps, MedianUser, SupportLauncherKindSupport widget
MedianSupportModalPropsSupport modal
MedianContactFormProps, MedianContactField, MedianContactFieldKind, MedianContactMessage, MedianContactOptions, MedianContactControl, UseMedianContactOptionsContact form
MedianFeedbackPropsFeedback panel
MedianSupportControl, MedianFeedbackControlControl from code
MedianSupportInstance, MedianSupportModalInstance, MedianContactFormInstance, MedianContactFormMountOptions, MedianFeedbackInstanceWithout React
MedianErrorReportOptions, MedianErrorReportOutcomeCrash reports
MedianDiagnosticsContext and diagnostics

The Portal* names from @tryportal/widget, such as PortalSupport, still work. They will be removed in a later major version.

Accessibility

The support panel and the modal handle these for you.

  • Every icon button has a label, such as Close support and Send message.
  • The launcher is labelled Chat with Acme support, plus the unread count when there is one.
  • The thread is a log region with aria-live="polite", so new replies are announced. The unread card is a polite status region.
  • Agent avatars are announced by name.
  • The closed panel is inert, so nothing in it takes focus.
  • Escape closes the panel. Focus moves into the panel on open. On close it returns to the launcher, or with launcher="hidden" to the element that opened the panel.

Still need help?

    Esc