Spread the picture on social media using Progressive Web App

I am currently working on a Nuxt PWA where I have implemented a function to convert HTML to Canvas using a specific package. The output generated is in base 64 format. My goal now is to find a way to easily share this image through various platforms such as Whatsapp, Facebook, email, and Instagram. Despite my efforts, most packages I found only support sharing URLs and text, not files.

Below is the code for my sharing function:

shareTicket(index) {
  html2canvas(this.$refs['ticket-' + index][0], {
    backgroundColor: '#efefef',
    useCORS: true,
  }).then((canvas) => {
    let url = canvas.toDataURL('image/png')

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

Removing the if (navigator.share) condition results in an error in the console stating that navigator.share is not a function. It has been mentioned that it only works with HTTPS, so I even tried uploading to a staging server, but the error persisted.

To clarify, my main objective is to directly share the actual generated image rather than just a URL link.

Answer №1

Could you please check if this URL is accessible to you:
If it is, you can access the Github repository here: https://github.com/kissu/so-share-image-bounty

The code snippet provided 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 implementation
      ;(async () => {
        if (!('share' in navigator)) {
          return
        }
        const canvas = await html2canvas(this.$refs.element)
        canvas.toBlob(async (blob) => {
          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>

Credit goes to @denvercoder9 for inspiration!


Additional Notes

  • I've utilized an Immediately Invoked Function Expression (IIFE) to work within the method context.
  • An asynchronous function was added for completeness and adherence to guidelines of ESlint.
  • I've employed $refs to accurately select DOM elements within Vue.
  • The solution was streamlined for simplicity, hosted securely on Netlify with HTTPS, and thoroughly tested on Chrome (v91).
  • For reference, here's the MDN documentation link for the Web Share API compatibility.

Web Browser Compatibility

My findings regarding browser compatibility based on testing are summarized in the table below:

Browser Support Status
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

While initially perceived as a mobile-specific feature, some desktop browsers surprisingly exhibit support for the Web Share API. It's noteworthy that Windows showed decent functionality in my tests. For further insights on browser support, refer to Google's post on browser compatibility.

In conclusion, based on the official definition from MDN:

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

Hence, the Share API seems more suited for mobile devices than desktop systems.

TLDR: The functionality performs as expected, but its compatibility across browsers remains relatively limited.

Answer №2

In my app, I have a customized version of the code snippet below placed within a share() function, which runs smoothly when executed on the client-side.

const share = async() => {
  if (!('share' in navigator)) {
    return;
  }
  // `element` represents the HTML element to be shared.
  // `backgroundColor` specifies the background color.
  const canvas = await html2canvas(element, {
    backgroundColor,
  });
  canvas.toBlob(async (blob) => {
    // Even for sharing a single file, it needs to be sent 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);            
    }
  });
};

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Retrieving AJAX data in a Node.js environment

In my HTML application, I am utilizing AJAX to showcase the output on the same page after the submit button is clicked. Before submitting, I am able to retrieve the values passed in the HTML form using: app.use(express.bodyParser()); var reqBody = r ...

What is the best way to eliminate "?" from the URL while transferring data through the link component in next.js?

One method I am utilizing to pass data through link components looks like this: <div> {data.map((myData) => ( <h2> <Link href={{ pathname: `/${myData.title}`, query: { ...

When using Vue.js testing, the toBe() method will only return an object when the expected value is a 'string' or other

I've been exploring the testing of Vue.js apps and recently focused on testing the data of my root component. Below is the code I have written: import { mount } from '@vue/test-utils' import App from '../../src/App' describe(&apo ...

Issue specifically with Android 6 WebView - jQuery 1.9.1 where a RangeError is thrown due to the call stack size being exceeded

An error message "Uncaught RangeError Maximum call stack size exceeded" is causing a web application to fail in the jQuery-1.9.1 extend() function, but strangely it only occurs on Android 6. The application runs smoothly on all other platforms such as Des ...

Obtain the content slot in Vue.js 2 and convert it into a string

Is it possible to retrieve the string inside a slot before that slot is compiled? For example: <div> <slot> <component-test text="test1"></component-test> </slot> </div> I am looking for the result "<co ...

The animation in an AngularJS directive only functions properly when utilizing $timeout

I can't seem to figure out why the animation is not working as intended in the code below: app.directive('openMenu', ['$animate', '$timeout', function($animate, $timeout) { return { link: function(scope, elem ...

encountering difficulties when trying to install npm packages in node.js

Starting out with Node.js and new to installing packages like express.js and underscore.js using NPM. However, every time I attempt to install using the following commands: npm install express, npm install underscore I keep encountering errors. Please ...

Tips for ensuring the directive stays current with changes to the parent scope variable

Example: <div ng-show="{{ display }}"> ... </div> angular.module('mymodule').directive('mydirective', [ function () { return { scope: { display: '=' }, ... }; ...

Unable to retrieve a response, the operation `users.findOne()` has exceeded the buffering time limit of 10000ms

I encountered an issue when attempting to make a POST login request. The frontend is deployed on Netlify here, and the backend is deployed on Heroku here. Here are my backend logs . I am receiving `users.findOne()` buffering timed out after 10000ms in ...

Headers with a 3 pixel stroke applied

I have a design on my website that includes a 3px stroke around the header text to maintain consistency. I don't want to use images for this due to issues with maintenance and site overhead. While I know about the text-stroke property, browser suppor ...

Tips for accessing a unique window name in JavaScript

How can I make window.name persist between page refreshes? I need to use window.name to differentiate between multiple browser windows, allowing each one to display distinct data while sharing the same URL. However, my problem is that the value of window ...

Even after configuring a proxy, the API calls are still not being redirected to the correct destination

Even after setting up a proxy, the API requests are not being directed to the correct target URL. I've built a chatbot application with create-react-app. My goal is to reroute all API calls originating from http://localhost:3000/ to http://localhost: ...

What exactly does Container-Based Authorization entail?

Did you know that the "XMLHttpRequest" object includes a method called "open," which has the option to supply a username and password? These parameters can be used for requests that require container-based authentication. Here is the method signature: op ...

Issue: The function (0, react__WEBPACK_IMPORTED_MODULE_1__.useActionState) is not recognized as a valid function or its output is not iterable

I found a great example of using useActionState at this source. Currently, I am implementing it in my project with Next.js and TypeScript. app/page.tsx: "use client"; import { useActionState } from "react"; import { createUser } from ...

Guide to watching a particular property in an array of objects using Vue

I am currently working with Vue.js version 2.5.2 My goal is to monitor changes in the forms[*].selected array of objects and trigger a function when it changes. I attempted to achieve this by using a for loop to watch each object's selected property ...

When attempting to make a GET request, Express/Mongoose is returning a null array

I am having trouble retrieving the list of books from my database. Even though I have successfully inserted the data into Mongoose Compass, when I try to fetch it, all I get is an empty array. //Model File import mongoose from "mongoose"; cons ...

Error occurred while retrieving JSON array using Jquery

var groupMembers = $.parseJSON(members); $.each(groupMembers, function (index, item) { $.ajax({ type: "POST", url: "'.base_url(" / panel / listNotifications ").'/'.$id.'/" + valueSelected, d ...

The error message "Unexpected token < in JSON at position 0" is indicating a SyntaxError in the

I am facing an issue with the API on this specific page. Although the API is working fine on other pages, it seems to be encountering a problem here. I'm not sure what's causing the issue. Below is the code snippet: export async function getStati ...

Retrieving data from the database using getStaticProps in Next.js

As I was following a tutorial on Next.js, the instructor did something that deviated from what I had learned in school and left me pondering. Here is what he did: interface FaqProps { faq: FaqModel[]; } export default function Faq({ faq }: FaqProps) { ...

Learn how to send or submit data using the Form.io form builder

I am currently working on a dynamic drag and drop form builder, and I'm struggling to figure out how to log the data from the form. Below is the component.html file where I am implementing the drag and drop form: <div> <form-builder ...