useShare
A cross-platform utility hook for invoking the native share sheet on mobile and desktop, enabling effortless content sharing with optional fallbacks.
Installation
npx shadcn@latest add https://r.fiberui.com/r/hooks/use-share.jsonA React hook that provides access to the Web Share API, allowing you to trigger the native share mechanism of the device (like the share sheet on iOS/Android).
Source Code
View the full hook implementation in the Hook Source Code section below.
Requirements
- Requires HTTPS (secure context). - Requires User Interaction (click handler) to trigger. - Support varies by browser/OS (mostly Mobile + Safari desktop).
Features
- Native Experience - Triggers the system share sheet users are familiar with
- File Sharing - Supports sharing files (images, pdfs, etc)
- Support Check -
isSupportedflag to conditionally render UI - Cancellation Handling - Gracefully handles user cancellation
- SSR Safe - Works safely with server-side rendering
Basic Usage
Share a title, text, and URL. This works on most mobile browsers and Safari on macOS.
"use client";
import { useShare } from "@repo/hooks/utility/use-share";
import { Button } from "@repo/ui/components/button";
import { Share2 } from "lucide-react";
import { toast } from "sonner";
export function Example1() {
const { share, isSupported } = useShare();
const handleShare = async () => {
const success = await share({
title: "Fiber UI Hooks",
text: "Check out this awesome collection of React hooks!",
url: "https://fiberui.com/hooks",
});
if (success) {
toast.success("Shared successfully!");
} else {
toast.error("Share cancelled or failed");
}
};
if (!isSupported) {
return (
<div className="rounded-md bg-yellow-100 p-4 text-yellow-800 dark:bg-yellow-900/30 dark:text-yellow-200">
Web Share API is not supported in this browser.
</div>
);
}
return (
<Button onClick={handleShare} className="gap-2">
<Share2 className="h-4 w-4" />
Share Resource
</Button>
);
}
API Reference
Hook Signature
function useShare(): UseShareReturn;ShareData Interface
interface ShareData {
title?: string; // Title of the shared content
text?: string; // Description text
url?: string; // URL to share
files?: File[]; // Array of File objects to share
}Return Value
| Property | Type | Description |
|---|---|---|
share | (data: ShareData) => Promise<boolean> | Triggers share sheet. Returns true if successful |
isSupported | boolean | true if Web Share API is available on current device |
isSharing | boolean | true while the share sheet is open (some browsers) |
canShare | (data: ShareData) => boolean | Checks if specific data (like files) can be shared |
error | Error | null | Error object if share failed or was cancelled |
Hook Source Code
import { useState, useCallback } from "react";
/**
* Options for the share data
*/
export interface ShareData {
/** Title of the shared content */
title?: string;
/** Text description of the shared content */
text?: string;
/** URL to share */
url?: string;
/** Array of files to share */
files?: File[];
}
/**
* Return type for the useShare hook
*/
export interface UseShareReturn {
/** Share data using the native share sheet */
share: (data: ShareData) => Promise<boolean>;
/** Whether sharing is supported */
isSupported: boolean;
/** Whether a share operation is in progress */
isSharing: boolean;
/** Error from the last share attempt */
error: Error | null;
/** Check if specific data can be shared */
canShare: (data: ShareData) => boolean;
}
/**
* A React hook for using the Web Share API to share content via the triggering device's native sharing mechanism.
*
* @returns UseShareReturn object with share function and state
*
* @example
* ```tsx
* const { share, isSupported } = useShare();
*
* return (
* <button onClick={() => share({ title: "Check this out", url: "https://example.com" })}>
* Share
* </button>
* );
* ```
*/
export function useShare(): UseShareReturn {
const [isSharing, setIsSharing] = useState(false);
const [error, setError] = useState<Error | null>(null);
// Check support
const isSupported =
typeof navigator !== "undefined" &&
typeof navigator.share === "function";
// Can share check
const canShare = useCallback((data: ShareData): boolean => {
if (
typeof navigator === "undefined" ||
typeof navigator.canShare !== "function"
) {
return false;
}
return navigator.canShare(data);
}, []);
// Share function
const share = useCallback(
async (data: ShareData): Promise<boolean> => {
if (!isSupported) {
setError(new Error("Web Share API is not supported"));
return false;
}
setIsSharing(true);
setError(null);
try {
await navigator.share(data);
return true;
} catch (err) {
// AbortError is common when user cancels, we treat it as an error but you might want to ignore it
const error =
err instanceof Error ? err : new Error("Failed to share");
setError(error);
return false;
} finally {
setIsSharing(false);
}
},
[isSupported],
);
return {
share,
isSupported,
isSharing,
error,
canShare,
};
}
export default useShare;
usePictureInPicture
A comprehensive hook for managing Picture-in-Picture mode for video elements, allowing creating floating video players that persist while multitasking.
useThrottledCallback
A hook that limits the rate at which a function activates. Ideal for optimizing scroll listeners and mouse movement handlers by enforcing a maximum execution frequency.