add external link UX: icons, rel attributes, screen reader labels

New external_link component in core_components handles target="_blank",
rel="noopener noreferrer", external-link icon, and sr-only "(opens in
new tab)" text. Migrated admin providers form, settings (Stripe),
order tracking, onboarding setup links to use it. Fixed rel="noopener"
to "noopener noreferrer" on remaining links (email settings, product
show, core_components card radio). Added sr-only text to shop social
link cards and aria-label to page renderer tracking link.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
jamey
2026-03-04 00:55:09 +00:00
parent 696843bacd
commit 156a23da16
12 changed files with 58 additions and 30 deletions

View File

@@ -423,6 +423,25 @@ defmodule BerrypodWeb.CoreComponents do
"""
end
@doc """
Renders a link to an external site with proper security attributes,
an external-link icon, and screen reader context.
"""
attr :href, :string, required: true
attr :class, :string, default: nil
attr :rest, :global
slot :inner_block, required: true
def external_link(assigns) do
~H"""
<a href={@href} target="_blank" rel="noopener noreferrer" class={@class} {@rest}>
{render_slot(@inner_block)}
<.icon name="hero-arrow-top-right-on-square" class="external-link-icon" />
<span class="sr-only">(opens in new tab)</span>
</a>
"""
end
## JS Commands
def show(js \\ %JS{}, selector) do
@@ -608,9 +627,10 @@ defmodule BerrypodWeb.CoreComponents do
:if={@option[:url]}
href={@option.url}
target="_blank"
rel="noopener"
rel="noopener noreferrer"
class="card-radio-link"
onclick="event.stopPropagation();"
aria-label={@option.name <> " (opens in new tab)"}
>
{@option.name} &nearr;
</a>

View File

@@ -431,6 +431,7 @@ defmodule BerrypodWeb.ShopComponents.Content do
<.social_icon platform={link.platform} />
</span>
<span>{link.label}</span>
<span class="sr-only">(opens in new tab)</span>
</a>
<% end %>
</div>