RORK LABJP
MAX — Rork Max builds native Swift apps for iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and iMessageNATIVE — Rork Max unlocks AR/LiDAR scanning, Metal 3D, widgets, Live Activities, HealthKit, and moreFUNDING — Rork raised $2.8M from a16z, now drawing 743k+ monthly visits at an 85% growth rateRN — Standard Rork generates iOS and Android apps together using React Native (Expo)FOCUS — Rork focuses solely on native mobile apps, setting it apart from web-first Bolt and LovablePRICING — Free to start, paid plans from $25/mo, with Rork Max at $200/mo and two-click App Store publishingMAX — Rork Max builds native Swift apps for iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and iMessageNATIVE — Rork Max unlocks AR/LiDAR scanning, Metal 3D, widgets, Live Activities, HealthKit, and moreFUNDING — Rork raised $2.8M from a16z, now drawing 743k+ monthly visits at an 85% growth rateRN — Standard Rork generates iOS and Android apps together using React Native (Expo)FOCUS — Rork focuses solely on native mobile apps, setting it apart from web-first Bolt and LovablePRICING — Free to start, paid plans from $25/mo, with Rork Max at $200/mo and two-click App Store publishing
Articles/App Dev
App Dev/2026-06-29Intermediate

Clipboard UX in Expo apps — copy and paste without flooding users with iOS's paste banner

When you wire up copy and paste with expo-clipboard, iOS's paste permission banner can fire constantly and quietly erode trust. Here's exactly when the banner appears, and how hasStringAsync lets you gate a Paste button without ever reading the contents.

Rork476Expo123ClipboardiOS87UX Design8

Premium Article

When I added an invite-code redemption screen to one of my wallpaper apps, a small banner reading "Pasted from [other app]" appeared at the top of the screen every single time the screen opened. Testers kept asking me, "Is this actually safe?" The cause was obvious in hindsight: trying to be helpful, I was reading the clipboard the moment the screen mounted and auto-filling the code field. The instant you read, that banner fires.

Clipboard integration looks like a trivial feature — copy one line of text — but without understanding iOS's behavior, it quietly turns your app into a noisy one. Let me walk through how to use expo-clipboard so the paste banner only shows when it makes sense, while copy and paste still feel smooth.

Where the paste banner actually comes from

This trips people up: copying (writing) and pasting (reading) are treated completely differently.

Writing — Clipboard.setStringAsync() — produces no notification at all. It happens because the user pressed a copy button, so that's expected. The reading side is where the trouble is. Since iOS 16, reading content another app copied via Clipboard.getStringAsync() shows a "Pasted from [app]" banner. It exists to tell the user "this app just peeked at your clipboard," and you cannot turn it off.

This is why when you read matters so much. My mistake was reading before the user had done anything — on mount. A read that happens right after the user taps "Paste" produces a banner that matches the context, so it doesn't feel intrusive. A read on open, or on a polling interval, fires banners the user can't account for, and that breeds suspicion.

ActionAPIiOS banner
Copy (write)setStringAsync()No
Read contents (paste)getStringAsync()Yes (iOS 16+)
Check presence onlyhasStringAsync()No

Use hasStringAsync to gate the button without reading

That last row is the key. hasStringAsync() returns a boolean for "is there a string on the clipboard" without ever reading the contents — so no banner. With it, you can disable the Paste button when the clipboard is empty and enable it only when something is there. You read the actual value only at the moment the user taps that button.

import { useEffect, useState } from "react";
import * as Clipboard from "expo-clipboard";
 
function RedeemCodeField({ onPaste }: { onPaste: (value: string) => void }) {
  const [canPaste, setCanPaste] = useState(false);
 
  // Checks presence only — never reads contents, so no banner
  useEffect(() => {
    let mounted = true;
    Clipboard.hasStringAsync().then((has) => {
      if (mounted) setCanPaste(has);
    });
    return () => {
      mounted = false;
    };
  }, []);
 
  // The real read happens only when the user taps the button
  const handlePaste = async () => {
    const text = await Clipboard.getStringAsync();
    if (text) onPaste(text.trim());
  };
 
  return (
    <PasteButton disabled={!canPaste} onPress={handlePaste} />
  );
}

Calling hasStringAsync() once on mount produces no banner. If you also want to re-check when the app returns to the foreground, call hasStringAsync() again from the AppState change event when state becomes active. You're still only checking presence, so it stays safe.

For something with a fixed shape like an invite code, don't drop the pasted string in verbatim. Run text.trim() to strip surrounding whitespace, then do a light validation against the expected format before applying it. That way the field doesn't break when a user accidentally copies extra characters along with the code.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
The exact conditions that trigger iOS's paste permission banner, and how to offer paste without multiplying it
An implementation pattern that uses hasStringAsync to enable a Paste button without reading the clipboard
Reliable copy feedback, plus how to clean up after putting sensitive data on the clipboard
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

App Dev2026-06-27
Before You Ask 'Are You Sure?' — Consider an Undoable Delete
Showing a confirmation dialog every time someone removes a list item trains them to tap OK without reading. Here is how to build an undoable delete in a Rork (Expo) app, and where confirmation dialogs still belong.
App Dev2026-06-29
Respecting Metered Connections and Low Data Mode in an Image-Heavy Rork App
In an image-heavy Rork (Expo) app, hold back prefetching on metered connections and Low Data Mode. Read the connection's character from NetInfo details, drop image quality, and defer prefetch with an adaptive policy layer, all with working code.
App Dev2026-06-27
Show the In-App 'What's New' Once, Without Nagging — Version Gating and Seen State
An in-app 'What's New' screen that fires on fresh installs or shows every launch gets users annoyed. Here is a version-gated, seen-state design that delivers it exactly once to people who updated — in real Rork (Expo) code, plus a shape you reuse across multiple apps.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →