or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

event-handling.mdimage-operations.mdindex.mdpaste-button.mdtext-operations.mdurl-operations.md
tile.json

paste-button.mddocs/

Paste Button Component (iOS 16+)

Native iOS paste button component providing permission-free clipboard access with customizable appearance. The ClipboardPasteButton displays the system UIPasteControl and only works on iOS 16 and later.

Capabilities

Paste Button Availability

Property indicating whether the ClipboardPasteButton component is available on the current platform.

/**
 * Property that determines if the ClipboardPasteButton is available.
 * This requires the user's device to be using at least iOS 16.
 * @returns true if the component is available, false otherwise
 */
const isPasteButtonAvailable: boolean;

Usage Examples:

import * as Clipboard from "expo-clipboard";

// Check availability before rendering
if (Clipboard.isPasteButtonAvailable) {
  console.log("Paste button is available");
} else {
  console.log("Paste button not available (requires iOS 16+)");
}

// Conditional rendering
const PasteSection = () => {
  if (!Clipboard.isPasteButtonAvailable) {
    return <Text>Paste button not available on this device</Text>;
  }
  
  return (
    <Clipboard.ClipboardPasteButton
      style={{ width: 200, height: 50 }}
      onPress={(data) => handlePaste(data)}
    />
  );
};

ClipboardPasteButton Component

React component that displays the native iOS UIPasteControl for permission-free clipboard access.

/**
 * This component displays the UIPasteControl button on your screen. This allows pasting 
 * from the clipboard without requesting permission from the user.
 * 
 * You should only attempt to render this if isPasteButtonAvailable is true. 
 * This component will render nothing if not available, with a warning in development mode.
 * 
 * The properties extend from View; however, you should not set backgroundColor, color 
 * or borderRadius with the style property. Use the dedicated props instead.
 * Make sure to attach height and width via style props as the button won't appear without them.
 */
function ClipboardPasteButton(props: ClipboardPasteButtonProps): JSX.Element | null;

interface ClipboardPasteButtonProps extends ViewProps {
  /** Callback called with the result of the paste action */
  onPress: (data: PasteEventPayload) => void;
  /** Background color of the button. Leaving as default allows system theme adjustment */
  backgroundColor?: string | null;
  /** Foreground color of the button */
  foregroundColor?: string | null;
  /** Corner style of the button */
  cornerStyle?: CornerStyleType | null;
  /** Display mode of the button */
  displayMode?: DisplayModeType | null;
  /** Custom style (should not include backgroundColor, borderRadius, or color) */
  style?: StyleProp<Omit<ViewStyle, 'backgroundColor' | 'borderRadius' | 'color'>>;
  /** Options to use when pasting an image from the clipboard */
  imageOptions?: GetImageOptions | null;
  /** Array of content types that will cause the button to become active */
  acceptedContentTypes?: AcceptedContentType[];
}

type PasteEventPayload = TextPasteEvent | ImagePasteEvent;

interface TextPasteEvent {
  text: string;
  type: 'text';
}

interface ImagePasteEvent extends ClipboardImage {
  type: 'image';
}

type AcceptedContentType = 'plain-text' | 'image' | 'url' | 'html';
type CornerStyleType = 'dynamic' | 'fixed' | 'capsule' | 'large' | 'medium' | 'small';
type DisplayModeType = 'iconAndLabel' | 'iconOnly' | 'labelOnly';

interface GetImageOptions {
  format: 'png' | 'jpeg';
  jpegQuality?: number;
}

Usage Examples:

import * as Clipboard from "expo-clipboard";
import { View, Text, Alert } from 'react-native';

// Basic paste button
const BasicPasteButton = () => {
  const handlePaste = (data: Clipboard.PasteEventPayload) => {
    if (data.type === 'text') {
      Alert.alert("Text Pasted", data.text);
    } else if (data.type === 'image') {
      Alert.alert("Image Pasted", `Size: ${data.size.width}x${data.size.height}`);
    }
  };

  if (!Clipboard.isPasteButtonAvailable) {
    return <Text>Paste button not available</Text>;
  }

  return (
    <Clipboard.ClipboardPasteButton
      style={{ width: 200, height: 50 }}
      onPress={handlePaste}
    />
  );
};

// Customized paste button
const CustomPasteButton = () => {
  const handlePaste = (data: Clipboard.PasteEventPayload) => {
    if (data.type === 'text') {
      console.log("Pasted text:", data.text);
    } else if (data.type === 'image') {
      console.log("Pasted image:", data.size);
    }
  };

  return (
    <Clipboard.ClipboardPasteButton
      style={{ 
        width: 250, 
        height: 60,
        alignSelf: 'center',
        marginVertical: 20
      }}
      backgroundColor="#007AFF"
      foregroundColor="white"
      cornerStyle="large"
      displayMode="iconAndLabel"
      acceptedContentTypes={['plain-text', 'image']}
      imageOptions={{ format: 'png' }}
      onPress={handlePaste}
    />
  );
};

// React hook for paste button management
const usePasteButton = () => {
  const [pastedContent, setPastedContent] = useState<string>("");
  const [pastedImage, setPastedImage] = useState<string | null>(null);

  const handlePaste = useCallback((data: Clipboard.PasteEventPayload) => {
    if (data.type === 'text') {
      setPastedContent(data.text);
      setPastedImage(null);
    } else if (data.type === 'image') {
      setPastedImage(data.data);
      setPastedContent(`Image: ${data.size.width}x${data.size.height}`);
    }
  }, []);

  return {
    pastedContent,
    pastedImage,
    handlePaste,
    isAvailable: Clipboard.isPasteButtonAvailable
  };
};

Configuration Options

Appearance Customization

// Corner styles (affects border radius)
cornerStyle: 'dynamic' | 'fixed' | 'capsule' | 'large' | 'medium' | 'small'

// Display modes (affects icon and label visibility)  
displayMode: 'iconAndLabel' | 'iconOnly' | 'labelOnly'

// Colors (null = system default)
backgroundColor: string | null  // Button background
foregroundColor: string | null  // Text and icon color

Content Type Filtering

// Specify which content types activate the button
acceptedContentTypes: ['plain-text', 'image', 'url', 'html']

// Default: ['plain-text', 'image']
// Note: Don't include both 'plain-text' and 'html' as this treats all text as HTML

Image Paste Options

// Configure image paste behavior
imageOptions: {
  format: 'png' | 'jpeg',
  jpegQuality?: number  // 0.0 to 1.0, only for JPEG
}

Platform Considerations

iOS 16+ Only

  • Availability: Only works on iOS 16 and later
  • System Integration: Uses native UIPasteControl component
  • Permissions: No clipboard permissions required (major benefit)
  • Appearance: Limited customization compared to custom components

Design Restrictions

  • Style Limitations: Cannot customize backgroundColor, borderRadius, or color via style prop
  • Required Dimensions: Must specify width and height in style prop
  • System Appearance: Button appearance follows iOS design guidelines
  • Text: The word "Paste" and icon are not customizable

Fallback Strategy

import * as Clipboard from "expo-clipboard";
import { Platform, TouchableOpacity, Text } from 'react-native';

const UniversalPasteButton = ({ onPaste }: { onPaste: (text: string) => void }) => {
  if (Clipboard.isPasteButtonAvailable) {
    // Use native paste button on iOS 16+
    return (
      <Clipboard.ClipboardPasteButton
        style={{ width: 200, height: 50 }}
        acceptedContentTypes={['plain-text']}
        onPress={(data) => {
          if (data.type === 'text') {
            onPaste(data.text);
          }
        }}
      />
    );
  } else {
    // Fallback for older iOS or other platforms
    return (
      <TouchableOpacity
        style={{ width: 200, height: 50, backgroundColor: '#007AFF' }}
        onPress={async () => {
          try {
            const text = await Clipboard.getStringAsync();
            onPaste(text);
          } catch (error) {
            console.log("Paste failed:", error);
          }
        }}
      >
        <Text style={{ color: 'white', textAlign: 'center' }}>Paste</Text>
      </TouchableOpacity>
    );
  }
};

Error Handling

The ClipboardPasteButton handles errors internally and will render nothing if not available, with warnings in development mode.

import * as Clipboard from "expo-clipboard";

// Safe rendering pattern
const SafePasteButton = () => {
  if (!Clipboard.isPasteButtonAvailable) {
    if (__DEV__) {
      console.warn("ClipboardPasteButton not available on this platform");
    }
    return null;
  }

  return (
    <Clipboard.ClipboardPasteButton
      style={{ width: 200, height: 50 }}
      onPress={(data) => {
        // Handle paste data
        console.log("Pasted:", data);
      }}
    />
  );
};