DEV Community

Cover image for Copy Text to Clipboard on Click React Component
Radzion Chachura
Radzion Chachura

Posted on • Originally published at radzion.com

Copy Text to Clipboard on Click React Component

Watch on YouTube | 🐙 GitHub | 🎮 Demo

Let's make a beautiful React component that will copy text to the clipboard on click. It shows a copy icon at the end to signify that you can interact with the text, it becomes brighter when hovered, and on click, the copy icon turns into a check icon.

Example from ReactKit

The CopyText component receives the same properties as the Text component plus content property that should contain the text to copy. To learn more about the reusable Text component, check out this post.

import { Text } from "lib/ui/Text"
import { CopyIcon } from "./icons/CopyIcon"
import styled from "styled-components"
import { getColor } from "./theme/getters"
import copy from "copy-to-clipboard"
import { defaultTransitionCSS } from "./animations/transitions"
import { useState } from "react"
import { Match } from "./Match"
import { CheckIcon } from "./icons/CheckIcon"

interface CopyTextProps extends React.ComponentProps<typeof Text> {
  content: string
}

const IconWr = styled(Text)`
  margin-left: 4px;
  ${defaultTransitionCSS};
  color: ${getColor("textSupporting3")};
`

const Container = styled(Text)`
  cursor: pointer;

  &:hover ${IconWr} {
    color: ${getColor("contrast")};
  }
`

type IconToShow = "copy" | "copied"

export const CopyText = ({ content, children, ...rest }: CopyTextProps) => {
  const [iconToShow, setIconToShow] = useState<IconToShow>("copy")

  return (
    <Container
      onMouseLeave={() => setIconToShow("copy")}
      onTouchEnd={() => setIconToShow("copy")}
      onClick={() => {
        copy(content)
        setIconToShow("copied")
      }}
      {...rest}
    >
      {children}
      <IconWr as="span">
        <Match
          value={iconToShow}
          copy={() => <CopyIcon />}
          copied={() => <CheckIcon />}
        />
      </IconWr>
    </Container>
  )
}
Enter fullscreen mode Exit fullscreen mode

The Container component modifies styles of the Text component by adding pointer cursor together with a hover effect that will change color of the IconWr component. Inside of the Container we place the children and the IconWr component that will show the copy icon or the check icon depending on the iconToShow state. The Match component is a simple helper that will render the content based on the value property. It is a better alternative to the switch statement.

import { ReactNode } from "react"

type MatchProps<T extends string | number | symbol> = Record<
  T,
  () => ReactNode
> & {
  value: T
}

export function Match<T extends string | number | symbol>(
  props: MatchProps<T>
) {
  const render = props[props.value]

  return <>{render()}</>
}
Enter fullscreen mode Exit fullscreen mode

For a better user experience we change the copy icon to the check icon on click and reset it back to the copy icon when user leaves the mouse on removes finger from the touch screen.

Top comments (3)

Collapse
 
undqurek profile image
undqurek • Edited

if you are looking for custom solution in Vanilla JS check this article:
dirask.com/posts/JavaScript-copy-t...

There are available 2 versions: modern and legacy.

Collapse
 
thumbone profile image
Bernd Wechner

Or, if you want more than text, you want styles too, then, consider:

github.com/bernd-wechner/Copy-with...

Collapse
 
uttam_py profile image
Uttam Sharma

If you want to use a third-party library, then go for 'react-use,' which has a 'useCopyToClipboard' hook that is easy to use.