Skip to content

useNavigatorShare

React hook to share content through the browser.

Add the hook via the CLI:

sh
npx @novajslabs/cli add useNavigatorShare
sh
npx @novajslabs/cli add useNavigatorShare
sh
pnpm dlx @novajslabs/cli add useNavigatorShare

Or copy and paste the code into your project:

ts
interface IShareData {
  title: string;
  text: string;
  url?: string;
  files?: File[];
}

const errorMessages: Record<string, string> = {
  NotAllowedError: "Permission to share denied.",
  AbortError: "The sharing action was aborted.",
  NotSupportedError: "Your browser does not support the sharing feature.",
  TypeError: "Error while sharing: incorrect data type.",
};

function checkPermission(files?: File[]) {
  if (!navigator.canShare) {
    throw new Error("Your browser does not support the sharing feature.");
  }

  if (!navigator.canShare({ files } || { files: [new File([], "")] })) {
    throw new Error(
      `Your browser does not allow sharing ${
        files ? "this type of " : ""
      } files.`
    );
  }
}

function surroundTryCatch(fn: (data: IShareData) => void | Promise<void>) {
  return async (data: IShareData) => {
    try {
      await fn(data);
    } catch (error: unknown) {
      if ((error as Error).name in errorMessages) {
        const message = `Error while sharing: ${
          errorMessages[(error as Error).name]
        }`;
        console.error(message);
      } else {
        throw error;
      }
    }
  };
}

export const useNavigatorShare = () => {
  async function shareInNavigator(data: IShareData) {
    if (data.files) checkPermission(data.files);

    await navigator.share({
      title: data.title,
      text: data.text ?? "",
      url: data.url ?? "",
      files: data.files ?? [],
    });
  }

  return {
    shareInNavigator: surroundTryCatch(shareInNavigator),
  };
};
js
const errorMessages = {
  NotAllowedError: "Permission to share denied.",
  AbortError: "The sharing action was aborted.",
  NotSupportedError: "Your browser does not support the sharing feature.",
  TypeError: "Error while sharing: incorrect data type.",
};

function checkPermission(files) {
  if (!navigator.canShare) {
    throw new Error("Your browser does not support the sharing feature.");
  }

  if (!navigator.canShare({ files } || { files: [new File([], "")] })) {
    throw new Error(
      `Your browser does not allow sharing ${
        files ? "this type of " : ""
      } files.`
    );
  }
}

function surroundTryCatch(fn) {
  return async (data) => {
    try {
      await fn(data);
    } catch (error) {
      if (error.name in errorMessages) {
        const message = `Error while sharing: ${errorMessages[error.name]}`;
        console.error(message);
      } else {
        throw error;
      }
    }
  };
}

export const useNavigatorShare = () => {
  async function shareInNavigator(data) {
    if (data.files) checkPermission(data.files);

    await navigator.share({
      title: data.title,
      text: data.text ?? "",
      url: data.url ?? "",
      files: data.files ?? [],
    });
  }

  return {
    shareInNavigator: surroundTryCatch(shareInNavigator),
  };
};

Requirements

React 16.8 or higher

Return values

shareInNavigator

Type: function

Parameters:

ts
interface IShareData {
  title: string;
  text: string;
  url?: string;
  files?: File[];
}

Triggers the sharing process using the provided data.

Example

tsx
import { useNavigatorShare } from "./hooks/useNavigatorShare";

const App = () => {
  const { shareInNavigator } = useNavigatorShare();

  const handleShare = async () => {
    const shareData = {
      title: "Check this out!",
      text: "This is a cool link you should visit.",
      url: "https://novajs.co",
      files: [
        new File(["Nova.js is amazing!"], "example.txt", {
          type: "text/plain",
        }),
      ],
    };

    try {
      await shareInNavigator(shareData);
      alert("File shared successfully!");
    } catch (error) {
      console.error(error);
      alert("There was an error trying to share the file.");
    }
  };

  return <button onClick={handleShare}>Share</button>;
};

export default App;

Use cases

Here are some use cases where this React hook is useful:

  • Sharing an article from a news website
  • Sharing images from a gallery app
  • Sharing a product page from an e-commerce site
  • Sharing a document from a file management system
  • Sharing an event invitation

Released under the MIT License.