ShareModal

A ShareModal is build with a design system components and guidelines that enables users to share a link or content effortlessly. It provides options to share via social media, copy the link, or send via email, ensuring a seamless and accessible sharing experience.

Quick Start

Installation
npm install @adaptavant/share-modal
Import
import { ShareModal } from '@adaptavant/share-modal';

Default

The Share Modal takes a link, title, description (primary and secondary), and optionLabels for built‑in actions like Copy Link, Email, Facebook, Messenger, and WhatsApp. It also connects onClose and closeButtonProps with an explicit label to improve screen‑reader clarity.
The ShareModal is responsive: from tablet breakpoint it converts to a bottom sheet, displaying the link as a QR code with Copy and native Share button.

Note:
headingImageProps has been deprecate as of 1.1.0, please use avatarProps

const [openModal, setOpenModal] = React.useState(false);

const closeModal = () => {
  setOpenModal(false);
};

return (
  <React.Fragment>
    <Button
      iconStart={ShareIcon}
      label="Share"
      onClick={() => {
        setOpenModal(true);
      }}
      size="standard"
      variant="neutralSecondary"
    >
      Share
    </Button>
    <ShareModal
      className="share-modal"
      closeButtonProps={{
        label: "Close share modal",
        onClick: closeModal,
      }}
      link="https://earth.anywhere.co/widgets"
      onClose={closeModal}
      open={openModal}
      translations={{
        description: {
          primary: "Earth Design System",
          secondary:
            "That’s here. An evolving digital ecosystem that we strive to care.",
        },
        optionLabels: {
          copyLabel: "Copy link",
          emailLabel: "Email",
          facebookLabel: "Facebook",
          messengerLabel: "Messenger",
          whatsappLabel: "WhatsApp",
        },
        title: "Share this page",
      }}
    />
  </React.Fragment>
);

Translations

Use the translations prop to localize the modal’s title and descriptions, and optionLabels to translate built‑in action buttons (Copy Link, Email, Facebook, Messenger, WhatsApp).

Note:
translations.content has been deprecate as of 1.1.0, please use translations.description.primary

const [openModal, setOpenModal] = React.useState(false);

const closeModal = () => {
  setOpenModal(false);
};

return (
  <React.Fragment>
    <Button
      iconStart={ShareIcon}
      label="Compartir"
      onClick={() => {
        setOpenModal(true);
      }}
      size="standard"
      variant="neutralSecondary"
    >
      Compartir
    </Button>
    <ShareModal
      className="share-modal"
      closeButtonProps={{
        label: "Cerrar modal de compartir",
        onClick: closeModal,
      }}
      link="https://earth.anywhere.co/widgets"
      onClose={closeModal}
      open={openModal}
      translations={{
        description: {
          primary: "Sistema de Diseño Earth",
          secondary:
            "Aquí está. Un ecosistema digital en evolución que nos esforzamos por cuidar.",
        },
        optionLabels: {
          copyLabel: "Copiar enlace",
          emailLabel: "Correo",
          facebookLabel: "Facebook",
          messengerLabel: "Messenger",
          whatsappLabel: "WhatsApp",
        },
        title: "Compartir esta página",
      }}
    />
  </React.Fragment>
);

With Custom Options

Use the shareOptions prop to include your own sharing buttons. Each option takes an icon, label, and onClick action—for example, opening a Twitter or LinkedIn share.

const [openModal, setOpenModal] = React.useState(false);

const closeModal = () => {
  setOpenModal(false);
};

return (
  <React.Fragment>
    <Button
      iconStart={ShareIcon}
      label="Share"
      onClick={() => {
        setOpenModal(true);
      }}
      size="standard"
      variant="neutralSecondary"
    >
      Share
    </Button>
    <ShareModal
      className="share-modal"
      closeButtonProps={{
        label: "Modal Close Button",
        onClick: closeModal,
      }}
      link="https://go.setmore.com"
      onClose={closeModal}
      open={openModal}
      shareOptions={[
        {
          icon: TwitterIcon,
          id: "share-via-twitter",
          label: "Twitter",
          onClick: () => {
            window.open(
              "https://twitter.com/intent/tweet?url=somelink",
              "_blank"
            );
          },
        },
        {
          icon: LinkedinIcon,
          id: "share-via-linkedin",
          label: "Linkedin",
          onClick: () => {
            window.open(
              "https://www.linkedin.com/sharing/share-offsite/?url=somelink",
              "_blank"
            );
          },
        },
      ]}
      translations={{
        description: { primary: "Share this page with" },
        optionLabels: {
          copyLabel: "Copy link",
          emailLabel: "Email",
        },
        title: "Share this page",
      }}
    />
  </React.Fragment>
);

Without Company Details

Omit both avatarProps and translations.description to hide the company details section entirely. The share options remain fully functional. This is useful in contexts where company branding is irrelevant, such as a PWA lander page.

const [openModal, setOpenModal] = React.useState(false);

const closeModal = () => {
  setOpenModal(false);
};

return (
  <React.Fragment>
    <Button
      iconStart={ShareIcon}
      label="Share"
      onClick={() => {
        setOpenModal(true);
      }}
      size="standard"
      variant="neutralSecondary"
    >
      Share
    </Button>
    <ShareModal
      closeButtonProps={{
        label: "Close share modal",
        onClick: closeModal,
      }}
      link="https://earth.anywhere.co/widgets"
      onClose={closeModal}
      open={openModal}
      translations={{
        optionLabels: {
          copyLabel: "Copy link",
          emailLabel: "Email",
          facebookLabel: "Facebook",
          messengerLabel: "Messenger",
          whatsappLabel: "WhatsApp",
        },
        title: "Share this page",
      }}
    />
  </React.Fragment>
);

Company Details with Avatar Toggle

Use state to toggle avatarProps and let users show or hide the company avatar. Pass avatarProps when the avatar should be visible and undefined when it should be hidden. The company details section (description text) remains visible when the avatar is hidden.

const [openModal, setOpenModal] = React.useState(false);
const [showAvatar, setShowAvatar] = React.useState(true);

const closeModal = () => {
  setOpenModal(false);
};

return (
  <React.Fragment>
    <Box as="section" className="flex gap-2">
      <Button
        iconStart={ShareIcon}
        label="Share"
        onClick={() => {
          setOpenModal(true);
        }}
        size="standard"
        variant="neutralSecondary"
      >
        Share
      </Button>
      <Button
        onClick={() => setShowAvatar((prev) => !prev)}
        size="standard"
        variant="neutralSecondary"
      >
        {showAvatar ? "Hide" : "Show"} Avatar
      </Button>
    </Box>
    <ShareModal
      avatarProps={
        showAvatar
          ? {
              label: "Company Logo",
              src: "https://assets.setmore.com/website/v2/images/favicon/tree-icon/favicon-96x96.png",
            }
          : undefined
      }
      closeButtonProps={{
        label: "Close share modal",
        onClick: closeModal,
      }}
      link="https://earth.anywhere.co/widgets"
      onClose={closeModal}
      open={openModal}
      translations={{
        title: 'Share this service',
        description: {
          primary: 'Product design consultation',
          secondary: 'https://booking.setmore.com/scheduleappointment/services/123456789123456789123456789',
        },
        optionLabels: {
          copyLabel: "Copy link",
          emailLabel: "Email",
          facebookLabel: "Facebook",
          messengerLabel: "Messenger",
          whatsappLabel: "WhatsApp",
        }
      }}
    />
  </React.Fragment>
);

API Reference

ShareModal

PropDefaultDescription
translations_object
Translations object for the ShareModal. title key is required. description and optionLabels are optional. If optionLabels are undefined then shareOption should be provided.
translations.title_string
title key is required prop
translations.description_object
description key is optional prop
translations.content_string

⚠️ Deprecated, use translations.description instead.

translations.description.primary_string
Primary text inside the share modal.
translations.description.secondary_string
Secondary text inside the share modal.
translations.optionLabels_copyLabel | emailLabel | facebookLabel | messengerLabel | whatsappLabel
All keys in optionLabels are optional, a default option will be rendered only if a corresponding key is provided.
onClose_function
Callback triggered on closing the share modal and will activate upon pressing "Esc" or clicking on the overlay.
onEscPress?_(event: KeyboardEvent) => void
Callback fired when "Esc" key is pressed along with onClose.
onOverlayClick?_function
Callback fired when the overlay is clicked along with onClose
closeOnEsc?trueboolean
If set to false, the share modal will not close when the Esc key is pressed, and the Esc keydown event along with the onClose callback won't be attached. Similarly, onEscPress will have no effect.
open_boolean
When set to true, the dialog will be mounted to DOM.
size?640number
The size of the Modal 'Dialog' box in pixels.
togglePoint?767number
The screen width at which the modal should switch to a mobile-friendly layout.

⚠️ Deprecated with backwards compatibility. The logic will be handled internally in future.

mobileFriendly?trueboolean
Indicates if the share modal should be render Sheet in responsive view.
closeOnOverlayClick?trueboolean
If set to false, the share modal will not close when the overlay is clicked, and the onClose callback won’t be attached. Similarly, onOverlayClick will have no effect.
avatarProps?_object
To render image before the heading, contains label and src
avatarProps.label_string
Aria label content for the image added before the heading.
avatarProps.src_string
Url content for the image added before the heading.

headingImageProps?

_

object

⚠️ Deprecated, use avatarProps instead.

To render image before the heading, contains label and src

headingImageProps.label

_

string

⚠️ Deprecated, use avatarProps.label instead.

Aria label content for the image added before the heading.

headingImageProps.src

_

string

⚠️ Deprecated, use avatarProps.src instead.

Url content for the image added before the heading.

link_string
Link to be shared
shareOptions?_Array of Objects
To have custom share options, If no share options are passed, the default share options will be displayed
closeButtonProps?_object
To render and customise share modal close button contains label and onClick
closeButtonProps.label_string
Aria label content for the close Icon button.
closeButtonProps.onClick_function
Callback function to be invoked when the close button is clicked.

Style API

Our design system components include style props that allow you to easily customize different parts of each component to match your design needs.

Please refer to the Style API documentation for more insights.

ShareModal parts

const [openModal, setOpenModal] = React.useState(false);

const closeModal = () => {
  setOpenModal(false);
};

return (
  <React.Fragment>
    <Button
      iconStart={ShareIcon}
      label="Share"
      onClick={() => {
        setOpenModal(true);
      }}
      size="standard"
      variant="neutralSecondary"
    >
      Share
    </Button>
    <ShareModal
      className="border-4"
      classNames={{
        title: "text-positive-secondary",
        modalHeader: "mx-2 rounded-md p-2 bg-positive-secondary",
        modalContent: "p-3 bg-caution-secondary",
        modalHeaderContent: "text-critical-secondary border-4 bg-critical-secondary-hover",
        modalWrapper: "z-10 bg-opacity-90",
      }}
      closeButtonProps={{
        label: "Close share modal",
        onClick: closeModal,
      }}
      link="https://go.setmore.com"
      onClose={closeModal}
      open={openModal}
      translations={{
        description: { primary: 'Share this page with' },
        optionLabels: {
          copyLabel: "Copy Link",
          emailLabel: "Email",
          facebookLabel: "Facebook",
          messengerLabel: "Messenger",
          whatsappLabel: "Whatsapp",
        },
        title: "Share this page",
      }}
    />
  </React.Fragment>
);

Stylable PartsDescription
rootThe container that wraps the share modal.
titleThe title displayed in the header of the share modal.
modalHeaderThe container that holds and organizes the heading components.
modalHeaderContentThe container that holds the heading text and icon.
modalWrapperThe container that wraps the whole modal element, acts as the overlay as well.
modalContentThe container that holds the main content within the modal body.

NOTE: The content style part has been removed. Use primaryDescription and secondaryDescription style parts instead for styling description text.

ShareModalChildren parts

const [openModal, setOpenModal] = React.useState(false);

const closeModal = () => {
  setOpenModal(false);
};

return (
  <React.Fragment>
    <Button
      iconStart={ShareIcon}
      label="Share"
      onClick={() => {
        setOpenModal(true);
      }}
      size="standard"
      variant="neutralSecondary"
    >
      Share
    </Button>
    <ShareModal
      className="border-4"
      classNames={{
        optionStack: 'bg-critical',
        optionButton: 'bg-positive',
        track: 'bg-caution',
        primaryDescription: 'text-link',
        secondaryDescription: 'text-body-16'
      }}
      closeButtonProps={{
        label: "Close share modal",
        onClick: closeModal,
      }}
      link="https://anywhereworks.com"
      onClose={closeModal}
      open={openModal}
      translations={{
        description: { primary: 'Anywhereworks', secondary: 'Help the world work Anywhere' },
        optionLabels: {
          copyLabel: "Copy Link",
          emailLabel: "Email",
          facebookLabel: "Facebook",
          messengerLabel: "Messenger",
          whatsappLabel: "Whatsapp",
        },
        title: "Share this page",
      }}
    />
  </React.Fragment>
);

Stylable PartsDescription
optionStackThe container that wraps the option buttons.
optionButtonThe style for option button.
trackThe container that holds and avatar the description.
primaryDescriptionThe style for primary text.
secondaryDrescriptionThe style for secondary text.

ShareSheetChildren parts

Note: The bottom sheet renders only on mobile. The qrCode and sheetWrapper style parts apply only while the sheet is visible.

const [openModal, setOpenModal] = React.useState(false);

const closeModal = () => {
  setOpenModal(false);
};

return (
  <React.Fragment>
    <Button
      iconStart={ShareIcon}
      label="Share"
      onClick={() => {
        setOpenModal(true);
      }}
      size="standard"
      variant="neutralSecondary"
    >
      Share
    </Button>
    <ShareModal
      className="border-4"
      classNames={{
        optionStack: 'bg-critical',
        optionButton: 'bg-positive',
        sheetWrapper: 'bg-caution',
        qrCode: 'fill-positive',
      }}
      closeButtonProps={{
        label: "Close share modal",
        onClick: closeModal,
      }}
      link="https://anywhereworks.com"
      onClose={closeModal}
      open={openModal}
      translations={{
        description: { primary: 'Anywhereworks', secondary: 'Help the world work Anywhere' },
        optionLabels: {
          copyLabel: "Copy Link",
          emailLabel: "Email",
          facebookLabel: "Facebook",
          messengerLabel: "Messenger",
          whatsappLabel: "Whatsapp",
        },
        title: "Share this page",
      }}
    />
  </React.Fragment>
);

Stylable PartsDescription
optionStackThe container that wraps the option buttons.
optionButtonThe style for option button.
sheetWrapperThe container that qrcode and buttons.
qrCodeThe style for qrcode.