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​