Hoppa till huvudinnehåll

Vad har jag kopierat?

· 3 min att läsa
Filip Tammergård
Programmerare på Frilans Finans

Har du någonsin kopierat något och direkt glömt vad det var?

TL;DR

  • navigator.clipboard.readText() returnerar ett Promise<string> med clipboardens nuvarande text.
  • Funktionen är bara tillgänglig i en säker kontext (HTTPS eller localhost), och läsningen måste ske under en användarinteraktion – därför är den kopplad till ett knappklick i stället för att köras vid sidladdning.
  • Anropet kan kasta fel (nekad behörighet, dokumentet saknar fokus, ingen clipboard tillgänglig …) så det hör alltid hemma i ett try/catch.

Klicka på knappen för att se vad du har i din clipboard just nu:

Clipboard-API:t

Webbläsaren exponerar användarens clipboard via navigator.clipboard. För att läsa det som text anropar vi readText, som returnerar ett Promise som löses till det som finns i clipboarden:

const text = await navigator.clipboard.readText()

Den raden kommer med några begränsningar som är värda att känna till.

Endast i säker kontext

navigator.clipboard är bara definierat i en säker kontext – HTTPS i produktion och localhost under utveckling. På vanlig HTTP är egenskapen undefined, så det är bra att feature-detecta med navigator.clipboard?.readText innan man försöker använda den.

Användarinteraktion krävs

Sidor får inte läsa clipboarden i bakgrunden. Läsningen måste ske medan webbläsaren hanterar en användarinteraktion – ett klick, ett tangenttryck eller liknande. Det är inte bara en rekommendation; annars avvisas promiset av webbläsaren. Första läsningen kan dessutom utlösa en behörighetsfråga, beroende på webbläsare.

Ett knappklick är det enklaste sättet att uppfylla det kravet:

async function read() {
try {
const value = await navigator.clipboard.readText()
setClipboard(value.trim())
} catch {
setClipboard("Kunde inte visa vad du har kopierat…")
}
}

trim() rensar bort mellanslag och radbrytningar i början och slutet, så en kopiering som bara består av till exempel ett mellanslag eller en radbrytning inte renderas som ett osynligt blank.

Varför try/catch är viktigt

readText kan misslyckas av flera skäl, och felet är svårt att förutspå inifrån komponenten:

  • Användaren nekade (eller saknar) behörighet att läsa clipboarden.
  • Sidan är inte i en säker kontext.
  • Webbläsaren är äldre än API:t.
  • Dokumentet saknar fokus – Firefox är särskilt strikt med det.

Ett enkelt catch räcker – för ett enkelt "visa min clipboard"-UI finns det inget meningsfullt att göra utöver att berätta att det inte gick.

Bara text

readText returnerar bara text. Om clipboarden innehåller en bild eller en fil blir resultatet en tom sträng. För de rikare fallen finns navigator.clipboard.read(), som returnerar ClipboardItem-objekt med de tillgängliga MIME-typerna.

Allt tillsammans

Hela React-komponenten ser ut så här:

import { useState } from "react"

function Clipboard() {
const [clipboard, setClipboard] = useState<string>()

async function read() {
try {
const value = await navigator.clipboard.readText()
setClipboard(value.trim())
} catch {
setClipboard("Kunde inte visa vad du har kopierat…")
}
}

return (
<div>
<button type="button" onClick={read}>
Visa vad jag kopierat
</button>
{clipboard !== undefined && (
<p>{clipboard || "Du har inte kopierat något…"}</p>
)}
</div>
)
}

Så nästa gång du undrar vad du har i din clipboard men vägrar att testa att klistra in någonstans kan du använda den här sidan i stället!

Referenser