Skip to main content

Copy to Clipboard

The Copy to Clipboard component allows users to quickly copy text to the clipboard without using context menus or keyboard shortcuts.

It’s commonly used to allow users to copy unique identifiers such as tokens and URLs.

note

There are certain circumstances when browser's API to interact with clipboard may throw an error (or reject the returned Promise), thus we recommend to always provide onError callback via props. For example, we could show a toast notification "Couldn't copy to the clipboard. Please try again.". See "Handle errors" below for an example.

Example

Live Editor
function Example() {
  const text = 'Sample text';

  const onCopy = text => {
    console.log(text);
  };

  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: Spacing10 }}>
      <span>{text}</span>
      <CopyToClipboard
        text={text}
        notificationMessage="Copied!"
        onCopy={onCopy}
      >
        <IconButton iconName="Clipboard" aria-label="copy" />
      </CopyToClipboard>
    </div>
  );
}
Result
Loading...

Usage Rules

Do:

  • Use a snackbar to notify users when a component wraps an element that will disappear on click.
  • Whenever possible, use the Clipboard icon with a trigger element.

Variants

Toast Notification

note
  • The implementation of ToastProvider and ToastContext has been moved to mfe-shell and mfe-shared-context, respectively.
  • Please import ToastContext from mfe-shared-context. We have wrapped all the mfe apps with ToastProvider at root level in mfe-shell.
  • All mfe apps are wrapped with ToastProvider from mfe-shell so you don't need to wrap your app one more time.

You can decide by yourself how to notify users we strongly recommend using a toast only if a trigger element will disappear on click.

Live Editor
function NotifyWithToast() {
  const text = 'Another sample text';

  const onCopy = text => {
    console.log(text);
  };

  return (
    <ToastProvider>
      <div style={{ display: 'flex', alignItems: 'center', gap: Spacing10 }}>
        <span>{text}</span>
        <CopyToClipboard
          notificationType="toast"
          text={text}
          notificationMessage="Copied!"
          onCopy={onCopy}
        >
          <IconButton iconName="Clipboard" aria-label="copy" />
        </CopyToClipboard>
      </div>
    </ToastProvider>
  );
}
Result
Loading...

Alternatively, you can use the copyToClipboard callback. You can get it from the useCopyToClipboard hook.

In that case, you should pass text and notificationMessage arguments into the copyToClipboard function, respectively. Additionally, this function can optionally receive the onCopy callback as the third argument.

Live Editor
function UseCallback() {
  const MyComponent = () => {
    const copyToClipboard = useCopyToClipboard(true, 'toast');

    const text = 'Text to copy';

    const onCopy = text => {
      console.log(text);
    };

    return (
      <div style={{ display: 'flex', alignItems: 'center', gap: Spacing10 }}>
        <span>{text}</span>
        <IconButton
          iconName="Clipboard"
          onClick={() => {
            copyToClipboard(text, 'Copied!', onCopy);
          }}
          aria-label="copy"
        />
      </div>
    );
  };

  return (
    <ToastProvider>
      <MyComponent />
    </ToastProvider>
  );
}
Result
Loading...

Tooltip Position

You can use tooltipPosition prop to specify Tooltip position inside Copy to Clipboard

Live Editor
function Example() {
  const text = 'Sample text';

  const onCopy = text => {
    console.log(text);
  };

  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: Spacing10 }}>
      <span>{text}</span>
      <CopyToClipboard
        text={text}
        notificationMessage="Copied!"
        onCopy={onCopy}
        tooltipPosition="auto"
      >
        <IconButton iconName="Clipboard" aria-label="copy" />
      </CopyToClipboard>
      <span>{text}</span>
      <CopyToClipboard
        text={text}
        notificationMessage="Copied!"
        onCopy={onCopy}
        tooltipPosition="bottom"
      >
        <IconButton iconName="Clipboard" aria-label="copy" />
      </CopyToClipboard>
    </div>
  );
}
Result
Loading...

Handling errors

Browser API to interact with clipboard returns a promise, which can get rejected instead of resolved. Ideally we should handle potential errors, for instance navigator.clipboard.writeText() rejects when the browser window is not focused.

To reproduce this, you might enable CPU throttling via the DEV tools and click on the copy icon, following it up with immediate change to another window with a hotkey, as otherwise enough time will pass for promise to successfully resolve.

Live Editor
function Example() {
  const CopyButton = () => {
    const text = 'Sample text';
    const { showToast } = useContext(ToastContext);

    const onCopy = (text) => {
      console.log(text);
    };

    const onError = (err) => {
      showToast("Couldn't copy to the clipboard. Please try again.");
    };

    return (
      <div style={{ display: 'flex', alignItems: 'center', gap: Spacing10 }}>
        <span>{text}</span>
        <CopyToClipboard
          text={text}
          notificationMessage="Copied!"
          onCopy={onCopy}
          onError={onError}
        >
          <IconButton iconName="Clipboard" aria-label="copy" />
        </CopyToClipboard>
      </div>
    );
  };

  return (
    <ToastProvider>
      <CopyButton />
    </ToastProvider>
  );
}
Result
Loading...

Props

CopyToClipboard

NameTypeDefault
children *
The trigger element.
ReactElement
notificationMessage *
Text to be shown in the notification
string
text *
Text to be copied to clipboard
string
notificationType
The type of component to be used for notification
"tooltip" | "snackbar" | "toast"
"tooltip"
onCopy
The callback will be executed after the text has copied
((text: string) => void)
onError
The callback executed when failed to copy
((err: Error) => void)
tooltipPosition
"left" | "right" | "auto" | "top" | "bottom"
zIndex
Add z-index rule to the tooltip component
number | "auto"
"auto"
* - the prop is required.