javascriptvue.jsnuxt.jshtml2canvasweb-share

Share image via social media from PWA


In my Nuxt PWA I have a function that converts my HTML to Canvas using this package. The generated image is in base 64. Now I want to be able to share that image via: Whatsapp, Facebook, email, Instagram etc. I have found several packages but they all don't seem to support sharing files only URLs and Text.

This is my share function:

shareTicket(index) {
  html2canvas(this.$refs['ticket-' + index][0], {
    backgroundColor: '#efefef',
    useCORS: true, // if the contents of screenshots, there are images, there may be a case of cross-domain, add this parameter, the cross-domain file to solve the problem
  }).then((canvas) => {
    let url = canvas.toDataURL('image/png') // finally produced image url

    if (navigator.share) {
      navigator.share({
        title: 'Title to be shared',
        text: 'Text to be shared',
        url: this.url,
      })
    }
  })

When I take out the if (navigator.share) condition I get an error in my console that navigator.share is not a function. I read somewhere that it only works on HTTPS so I uploaded to my staging server and tried but still got the same error.

Just to be clear I want to be able to share the generated image itself and not a URL.


Solution

  • Tell me if this URL works for you: https://nuxt-share-social-media.netlify.app
    If it does, you can find the Github repo here: https://github.com/kissu/so-share-image-bounty

    The code is

    <template>
      <div>
        <div id="capture" ref="element" style="padding: 10px; background: #f5da55">
          <h4 style="color: #000">Hello world!</h4>
        </div>
    
        <br />
        <br />
        <button @click="share">share please</button>
      </div>
    </template>
    
    <script>
    import html2canvas from 'html2canvas'
    
    export default {
      methods: {
        share() {
          // iife here
          ;(async () => {
            if (!('share' in navigator)) {
              return
            }
            // `element` is the HTML element you want to share.
            // `backgroundColor` is the desired background color.
            const canvas = await html2canvas(this.$refs.element)
            canvas.toBlob(async (blob) => {
              // Even if you want to share just one file you need to
              // send them as an array of files.
              const files = [new File([blob], 'image.png', { type: blob.type })]
              const shareData = {
                text: 'Some text',
                title: 'Some title',
                files,
              }
              if (navigator.canShare(shareData)) {
                try {
                  await navigator.share(shareData)
                } catch (err) {
                  if (err.name !== 'AbortError') {
                    console.error(err.name, err.message)
                  }
                }
              } else {
                console.warn('Sharing not supported', shareData)
              }
            })
          })()
        },
      },
    }
    </script>
    

    Inspired from @denvercoder9!


    More info about the answer


    Compatibility

    This is my experience for the browsers (tested on the MDN example and on my app, exact same results)

    where working
    iPad chrome yes
    iPad firefox yes
    iPad safari yes
    windows chrome yes
    windows firefox no
    android chrome yes
    android firefox no
    desktop linux chrome no
    desktop linux firefox no

    For me, this was a mobile only feature (like for Android). But it looks like even some desktop browsers are handling this too. I have to admit that I was really surprised to even see this one work on Windows.
    Here is an interesting post from Google that correlates this compatibility: https://web.dev/web-share/#browser-support

    Reading MDN again, it says

    The navigator.share() method of the Web Share API invokes the native sharing mechanism of the device.

    So, I guess that the "(desktop) device" mostly do not support the Share API.

    TLDR: this is working totally as intended but the compatibility is really subpar so far.