Use Copy Clipboard

A Rust/UI hook that copies text to clipboard with optional timeout to show copied state.

utils
  • Rust/UI Icons - CopyCopy Demo
use icons::{Check, Copy};
use leptos::prelude::*;

use crate::components::hooks::use_copy_clipboard::use_copy_clipboard;
use crate::components::ui::button::{Button, ButtonVariant};
use crate::components::ui::input::Input;

#[component]
pub fn DemoUseCopyToClipboard() -> impl IntoView {
    let url = RwSignal::new("https://rust-ui.com/docs/components/input");
    let (copy_to_clipboard, copied) = use_copy_clipboard(Some(2000));

    let handle_copy = move |_| {
        copy_to_clipboard(url.get());
    };

    view! {
        <div class="flex gap-2">
            <Input prop:value=move || url().to_string() attr:readonly=true class="flex-1" />

            <Button variant=ButtonVariant::Outline on:click=handle_copy>
                {move || { if copied.get() { view! { <Check /> }.into_any() } else { view! { <Copy /> }.into_any() } }}
            </Button>
        </div>
    }
}

Installation

You can run either of the following commands:

# cargo install ui-cli --force
ui add demo_use_copy_clipboard
ui add use_copy_clipboard

Update the imports to match your project setup.

Copy and paste the following code into your project:

components/ui/use_copy_clipboard.rs

use leptos::prelude::*;
use wasm_bindgen::prelude::*;
use web_sys::window;

const DEFAULT_TIMEOUT_MS: i32 = 2000;

/// Hook for copying text to clipboard with optional delay
///
/// Returns a tuple of (copy_fn, copied_signal) where:
/// - `copy_fn`: Function that takes text to copy
/// - `copied_signal`: ReadSignal<bool> indicating if text was recently copied
pub fn use_copy_clipboard(timeout_ms: Option<i32>) -> (impl Fn(&str) + Clone, ReadSignal<bool>) {
    let copied = RwSignal::new(false);
    let timeout = timeout_ms.unwrap_or(DEFAULT_TIMEOUT_MS);

    let copy_to_clipboard = {
        move |text: &str| {
            if let Some(window) = window() {
                let navigator = window.navigator();
                let clipboard = navigator.clipboard();
                let _ = clipboard.write_text(text);

                // Set copied state to true
                copied.set(true);

                // Reset to false after timeout
                let copied_clone = copied;
                let closure = Closure::once_into_js(move || {
                    copied_clone.set(false);
                });
                let _ = window
                    .set_timeout_with_callback_and_timeout_and_arguments_0(closure.as_ref().unchecked_ref(), timeout);
            }
        }
    };

    (copy_to_clipboard, copied.read_only())
}

Update the imports to match your project setup.

Usage

use crate::components::hooks::use_copy_clipboard::use_copy_clipboard;
let (copy_to_clipboard, copied) = use_copy_clipboard(Some(2000));

// Copy text to clipboard
copy_to_clipboard("text to copy".to_string());

// Check if recently copied
if copied.get() {
    // Show copied state
}