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:
headingImagePropshas been deprecate as of1.1.0, please useavatarProps
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.contenthas been deprecate as of1.1.0, please usetranslations.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
| Prop | Default | Description |
|---|---|---|
translations | _ | objectTranslations object for the ShareModal. title key is required. description and optionLabels are optional. If optionLabels are undefined then shareOption should be provided. |
translations.title | _ | stringtitle key is required prop |
translations.description | _ | objectdescription key is optional prop |
translations.content | _ | string
|
translations.description.primary | _ | stringPrimary text inside the share modal. |
translations.description.secondary | _ | stringSecondary text inside the share modal. |
translations.optionLabels | _ | copyLabel | emailLabel | facebookLabel | messengerLabel | whatsappLabelAll keys in optionLabels are optional, a default option will be rendered only if a corresponding key is provided. |
onClose | _ | functionCallback triggered on closing the share modal and will activate upon pressing "Esc" or clicking on the overlay. |
onEscPress? | _ | (event: KeyboardEvent) => voidCallback fired when "Esc" key is pressed along with onClose. |
onOverlayClick? | _ | functionCallback fired when the overlay is clicked along with onClose |
closeOnEsc? | true | booleanIf 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 | _ | booleanWhen set to true, the dialog will be mounted to DOM. |
size? | 640 | numberThe size of the Modal 'Dialog' box in pixels. |
togglePoint? | 767 | numberThe screen width at which the modal should switch to a mobile-friendly layout.
|
mobileFriendly? | true | booleanIndicates if the share modal should be render Sheet in responsive view. |
closeOnOverlayClick? | true | booleanIf 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? | _ | objectTo render image before the heading, contains label and src |
avatarProps.label | _ | stringAria label content for the image added before the heading. |
avatarProps.src | _ | stringUrl content for the image added before the heading. |
| _ |
To render image before the heading, contains |
| _ |
Aria label content for the image added before the heading. |
| _ |
Url content for the image added before the heading. |
link | _ | stringLink to be shared |
shareOptions? | _ | Array of ObjectsTo have custom share options, If no share options are passed, the default share options will be displayed |
closeButtonProps? | _ | objectTo render and customise share modal close button contains label and onClick |
closeButtonProps.label | _ | stringAria label content for the close Icon button. |
closeButtonProps.onClick | _ | functionCallback 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 Parts | Description |
|---|---|
| root | The container that wraps the share modal. |
| title | The title displayed in the header of the share modal. |
| modalHeader | The container that holds and organizes the heading components. |
| modalHeaderContent | The container that holds the heading text and icon. |
| modalWrapper | The container that wraps the whole modal element, acts as the overlay as well. |
| modalContent | The container that holds the main content within the modal body. |
NOTE: The
contentstyle part has been removed. UseprimaryDescriptionandsecondaryDescriptionstyle 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 Parts | Description |
|---|---|
| optionStack | The container that wraps the option buttons. |
| optionButton | The style for option button. |
| track | The container that holds and avatar the description. |
| primaryDescription | The style for primary text. |
| secondaryDrescription | The style for secondary text. |
ShareSheetChildren parts
Note: The bottom sheet renders only on mobile. The
qrCodeandsheetWrapperstyle 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 Parts | Description |
|---|---|
| optionStack | The container that wraps the option buttons. |
| optionButton | The style for option button. |
| sheetWrapper | The container that qrcode and buttons. |
| qrCode | The style for qrcode. |