Corex.Clipboard (Corex v0.2.0)

View Source

Copy-to-clipboard control for Phoenix LiveView. Behavior follows Zag.js Clipboard. Set value for the initial string to copy. Use Corex.Clipboard.set_value/2 or corex:clipboard:set-value to change it on the client.

Anatomy

Minimal

<.clipboard class="clipboard" value="hello@example.com">
  <:label>Email</:label>
  <:copy>
    <.heroicon name="hero-clipboard" />
  </:copy>
  <:copied>
    <.heroicon name="hero-check" />
  </:copied>
</.clipboard>

Trigger only

<.clipboard
  class="clipboard"
  value="https://example.com/share"
  input={false}
  trigger_aria_label="Copy link"
>
  <:copy>
    <.heroicon name="hero-clipboard" />
  </:copy>
  <:copied>
    <.heroicon name="hero-check" />
  </:copied>
</.clipboard>

API

Requires a stable id on <.clipboard>.

FunctionActionReturns
copy/1Copy current value (client)%Phoenix.LiveView.JS{}
copy/2Copy current value (server)socket
set_value/2Set value to copy (client)%Phoenix.LiveView.JS{}
set_value/3Set value to copy (server)socket

Events

Pick an event name and pass it to on_* on <.clipboard>.

Server events

EventWhenPayload
on_copy="clipboard_copied"User copies%{"id" => id, "value" => value}

on_copy

<.clipboard
  class="clipboard"
  value="info@netoum.com"
  on_copy="clipboard_copied"
>
  <:label>Copy</:label>
  <:copy>
    <.heroicon name="hero-clipboard" />
  </:copy>
  <:copied>
    <.heroicon name="hero-check" />
  </:copied>
</.clipboard>
def handle_event("clipboard_copied", %{"value" => value, "id" => _id}, socket) do
  {:noreply, assign(socket, :last_copied, value)}
end

Client events

EventWhenevent.detail
on_copy_client="clipboard-copied"User copiesid, value

Style

Target parts with data-scope and data-part, or use Corex Design: import tokens and clipboard.css, then set class="clipboard" on <.clipboard>.

[data-scope="clipboard"][data-part="root"] {}
[data-scope="clipboard"][data-part="trigger"] {}
[data-scope="clipboard"][data-part="control"] {}
[data-scope="clipboard"][data-part="input"] {}
[data-scope="clipboard"][data-part="copy"] {}
[data-scope="clipboard"][data-part="copied"] {}
@import "../corex/corex.css";

Stack modifiers on the host (class on <.clipboard>). Combine axes, for example clipboard ui-accent ui-size-lg or clipboard ui-info ui-solid.

Axes: Semantic (ui-accent, ui-brand, ui-alert, ui-info, ui-success), Variant (ui-solid), Size (ui-size-smui-size-xl), Radius (ui-rounded-*). See the modifier guide.

Semantic modifiers set palette variables on the trigger. Variant modifiers control trigger surface treatment. Default is subtle. Copied feedback tints the input and trigger border and text only (surface stays on the UI tokens). Default copied palette is success; add a semantic modifier to override.

Semantic

Palette variables for clipboard ink and fill. Does not change surface treatment by itself.

ModifierClasses
Default (success on copy)clipboard
Accentclipboard ui-accent
Brandclipboard ui-brand
Alertclipboard ui-alert
Infoclipboard ui-info
Successclipboard ui-success

Variant

Visual treatment of the copy trigger. Combine with a semantic modifier for palette-driven ink and fill.

ModifierClasses
Subtle (default)clipboard or clipboard ui-accent
Solidclipboard ui-accent ui-solid

Size

ModifierClasses
SMclipboard ui-size-sm
MDclipboard ui-size-md
LGclipboard ui-size-lg
XLclipboard ui-size-xl

Summary

Components

Renders a clipboard component.

API

Copy the component's current value from a control (phx-click).

Copy the current value from handle_event.

Set the string to copy from a control (phx-click).

Set the value to copy from handle_event.

Components

clipboard(assigns)

Renders a clipboard component.

Attributes

  • id (:string) - The id of the clipboard, useful for API to identify the clipboard.
  • value (:string) - The value shown in the input and copied (initial or after client set_value). Defaults to nil.
  • timeout (:integer) - The timeout in milliseconds before resetting the copied state. Defaults to nil.
  • dir (:string) - The direction of the clipboard. When nil, derived from document (html lang + config :rtl_locales). Defaults to nil. Must be one of nil, "ltr", or "rtl".
  • orientation (:string) - Layout orientation for CSS. Defaults to "horizontal". Must be one of "horizontal", or "vertical".
  • on_copy (:string) - The server event name when the value is copied. Defaults to nil.
  • on_copy_client (:string) - The client event name when the value is copied. Defaults to nil.
  • trigger_aria_label (:string) - Accessible name for the trigger button when it contains only an icon (e.g. "Copy to clipboard"). Defaults to nil.
  • input_aria_label (:string) - Accessible name for the input when it's not associated with a visible label (e.g. "Value to copy"). Defaults to nil.
  • input (:boolean) - Whether to render the input element. Set to false when using only the trigger to copy. Defaults to true.
  • input_class (:string) - Defaults to nil.
  • control_class (:string) - Defaults to nil.
  • root_class (:string) - Defaults to nil.
  • Global attributes are accepted.

Slots

  • label - Accepts attributes:
    • class (:string)
  • copy - Accepts attributes:
    • class (:string)
  • copied - Accepts attributes:
    • class (:string)
  • trigger - Accepts attributes:
    • class (:string)

API

copy(clipboard_id)

@spec copy(String.t()) :: Phoenix.LiveView.JS.t()

Copy the component's current value from a control (phx-click).

<.action phx-click={Corex.Clipboard.copy("my-clipboard")}>Copy</.action>
<.clipboard id="my-clipboard" class="clipboard" value="hello@example.com">
  <:label>Email</:label>
  <:copy><.heroicon name="hero-clipboard" /></:copy>
  <:copied><.heroicon name="hero-check" /></:copied>
</.clipboard>
document.getElementById("my-clipboard")?.dispatchEvent(
  new CustomEvent("corex:clipboard:copy", { bubbles: false })
);

copy(socket, clipboard_id)

Copy the current value from handle_event.

<.action phx-click="copy_email">Copy</.action>
<.clipboard id="my-clipboard" class="clipboard" value="hello@example.com">
  <:label>Email</:label>
  <:copy><.heroicon name="hero-clipboard" /></:copy>
  <:copied><.heroicon name="hero-check" /></:copied>
</.clipboard>
def handle_event("copy_email", _, socket) do
  {:noreply, Corex.Clipboard.copy(socket, "my-clipboard")}
end

set_value(clipboard_id, value)

@spec set_value(String.t(), String.t()) :: Phoenix.LiveView.JS.t()

Set the string to copy from a control (phx-click).

<.action phx-click={Corex.Clipboard.set_value("my-clipboard", "next@example.com")}>Load</.action>
<.clipboard id="my-clipboard" class="clipboard" value="hello@example.com">
  <:label>Email</:label>
  <:copy><.heroicon name="hero-clipboard" /></:copy>
  <:copied><.heroicon name="hero-check" /></:copied>
</.clipboard>
document.getElementById("my-clipboard")?.dispatchEvent(
  new CustomEvent("corex:clipboard:set-value", {
    bubbles: false,
    detail: { value: "next@example.com" },
  })
);

set_value(socket, clipboard_id, value)

Set the value to copy from handle_event.

<.action phx-click="load_clipboard" phx-value-value="next@example.com">Load</.action>
<.clipboard id="my-clipboard" class="clipboard" value="hello@example.com">
  <:label>Email</:label>
  <:copy><.heroicon name="hero-clipboard" /></:copy>
  <:copied><.heroicon name="hero-check" /></:copied>
</.clipboard>
def handle_event("load_clipboard", %{"value" => value}, socket) do
  {:noreply, Corex.Clipboard.set_value(socket, "my-clipboard", value)}
end