Skip to content

Commit

Permalink
Add live region to announce "Copied!" on ClipboardCopy component (#2843)
Browse files Browse the repository at this point in the history
Co-authored-by: Cameron Dutro <camertron@gmail.com>
  • Loading branch information
lindseywild and camertron committed May 16, 2024
1 parent 004bf5c commit 3eccd4e
Show file tree
Hide file tree
Showing 7 changed files with 42 additions and 7 deletions.
5 changes: 5 additions & 0 deletions .changeset/afraid-shoes-taste.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@primer/view-components": minor
---

Adds live region to announce "Copied!" on ClipboardCopy component
15 changes: 9 additions & 6 deletions app/components/primer/beta/clipboard_copy.html.erb
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
<%= render Primer::BaseComponent.new(**@system_arguments) do %>
<% if content.present? %>
<%= content %>
<% else %>
<%= render Primer::Beta::Octicon.new(:copy) %>
<%= render Primer::Beta::Octicon.new(:check, color: :success, style: "display: none;") %>
<%= render Primer::BaseComponent.new(tag: :span) do %>
<%= render Primer::BaseComponent.new(**@system_arguments) do %>
<% if content.present? %>
<%= content %>
<% else %>
<%= render Primer::Beta::Octicon.new(:copy) %>
<%= render Primer::Beta::Octicon.new(:check, color: :success, style: "display: none;") %>
<% end %>
<% end %>
<div aria-live="polite" aria-atomic="true" class="sr-only" data-clipboard-copy-feedback></div>
<% end %>
2 changes: 2 additions & 0 deletions app/components/primer/beta/clipboard_copy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ module Beta
#
# @accessibility
# Always set an accessible label to help the user interact with the component.
#
# This component has a built-in `aria-live` region that announces "Copied!" when the copy element is pressed.
class ClipboardCopy < Primer::Component
status :beta

Expand Down
14 changes: 14 additions & 0 deletions app/components/primer/beta/clipboard_copy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,26 @@ document.addEventListener('clipboard-copy', ({target}) => {
if (!target.hasAttribute('data-view-component')) return

const currentTimeout = clipboardCopyElementTimers.get(target)
const clipboardCopyLiveRegion = target.parentNode?.querySelector<HTMLElement>('[data-clipboard-copy-feedback]')
const copiedAnnouncement = 'Copied!'

if (currentTimeout) {
clearTimeout(currentTimeout)
clipboardCopyElementTimers.delete(target)
} else {
showCheck(target)
if (clipboardCopyLiveRegion) {
if (clipboardCopyLiveRegion.textContent === copiedAnnouncement) {
/* This is a hack due to the way the aria live API works.
A screen reader will not read a live region again
if the text is the same. Adding a space character tells
the browser that the live region has updated,
which will cause it to read again, but with no audible difference. */
clipboardCopyLiveRegion.textContent = `${copiedAnnouncement}\u00A0`
} else {
clipboardCopyLiveRegion.textContent = copiedAnnouncement
}
}
}

clipboardCopyElementTimers.set(
Expand Down
2 changes: 2 additions & 0 deletions app/components/primer/beta/clipboard_copy_button.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ module Beta
# `ClipboardCopyButton` uses the `ClipboardCopy` component to copy text to the clipboard,
# styled as a Primer button. It can be used wherever a button is desired, and works well
# with components like `ButtonGroup`.
# @accessibility
# This component has a built-in `aria-live` region that announces "Copied!" when the copy button is pressed.
class ClipboardCopyButton < Primer::Beta::Button
# @param system_arguments [Hash] The arguments accepted by <%= link_to_component(Primer::Beta::Button) %> and <%= link_to_component(Primer::Beta::ClipboardCopy) %>.
def initialize(**system_arguments)
Expand Down
6 changes: 6 additions & 0 deletions test/components/beta/clipboard_copy_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,10 @@ def test_renders_with_for
assert_selector("svg.octicon.octicon-check.color-fg-success", visible: false)
end
end

def test_renders_aria_live_region
render_inline Primer::Beta::ClipboardCopy.new(value: "my-branch-name", "aria-label": "Copy branch name to clipboard")

assert_selector("[data-clipboard-copy-feedback]")
end
end
5 changes: 4 additions & 1 deletion test/system/beta/clipboard_copy_button_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,20 @@ class IntegrationClipboardCopyButtonTest < System::TestCase
def test_copies_text
visit_preview(:playground)

assert_selector("[data-clipboard-copy-feedback]", text: "", visible: :false)

clipboard_text = capture_clipboard do
find("#clipboard-button").click
end

assert_equal "Text to copy", clipboard_text
assert_selector("[data-clipboard-copy-feedback]", text: "Copied!", visible: :false)
end

def test_includes_tooltip
visit_preview(:with_tooltip)

assert_selector ".Button + tool-tip", visible: :all
assert_selector "tool-tip[for='clipboard-button']", visible: :all
end
end
end

0 comments on commit 3eccd4e

Please sign in to comment.