We’ve migrated our documentation to a new site, which means some URLs have changed.
Subscriptions

Accessibility Compliance

Starting June 2025, the European Accessibility Act (EAA) will take full effect, introducing stricter compliance requirements for digital accessibility across the EU. In Germany, this is enforced through the Barrierefreiheitsstärkungsgesetz (BFSG).

This legislation mandates that all digital services - including websites and user interfaces - comply with the Web Content Accessibility Guidelines (WCAG) 2.2, specifically at the AA level, to ensure equitable access for people with disabilities.

📘 For more information, visit the official W3C accessibility guidelines here.

Requirements

Below is an overview of key accessibility requirements that must be reflected in digital templates and user experiences:

  • Accessible Design
    Templates must be designed to be perceivable, operable, and understandable by users with disabilities.

  • Readability
    Text content must offer sufficient contrast, appropriate font size, and spacing to enhance readability.

  • User-Friendliness
    Interfaces should be intuitive, with clear labels and instructions to assist all users in navigating and completing actions.

  • Keyboard & Screen Reader Support
    All functionality and content must be fully navigable via keyboard, with screen readers providing accurate, meaningful feedback.

  • Multimedia Accessibility
    Videos and audio content should include subtitles, captions, or transcripts to accommodate users with hearing impairments.

  • Responsive Design
    Templates should function well across a range of devices and screen sizes, including tablets and smartphones.

  • Testing and Validation
    Templates must be tested and validated against WCAG 2.2 AA standards before being published or made available to end users.

📘 For a detailed breakdown of the WCAG 2.2 criteria, visit this link.

What This Means for Piano Clients

Piano has reviewed and is actively updating its default templates to meet these accessibility standards. Areas of focus include:

  • Contrast & Font Adjustments
    Verified using tools like WebAIM Contrast Checker and Color Contrast Analyzer.

  • Text Scaling
    Switching from px to em units for font sizing, allowing browser-level scaling.

  • Semantic HTML & ARIA Attributes
    Ensuring fields, form elements, and interactive controls are fully labeled and accessible.

  • Enhanced Keyboard Navigation
    Logical tab ordering, skip links, correct focus handling, and support for common key interactions (e.g., space/enter on buttons).

  • Screen Reader Feedback
    Including accessible descriptions, live region updates, and proper associations for error messages and modal content.

Wherever possible, we aim to roll out these improvements without requiring action on the client side. However:

  • If you've customized your templates, we recommend testing the updates in your Sandbox environment to validate compatibility and prevent layout breaks.

  • If needed, you can revert to Piano’s default templates or manually apply updates to align with WCAG requirements.

Accessibility is an ongoing initiative. We will continue to evolve our designs and functionality to meet changing legal standards and best practices - helping ensure your digital offerings remain inclusive, compliant, and future-proof.

Custom Screen Reader Announcer

While announcing "login success" via the screen reader isn’t part of our default accessibility features, clients looking to enhance accessibility can manually implement this feature. This involves adding a small script to make screen readers announce "login success" upon successful login. This adjustment is optional and can be implemented as follows:

// add function to script where pianoid inits
function showScreenReaderAnnouncer(message) {
          let announcer;
          if (document.getElementById('sr-announcements')) {
            announcer = document.getElementById('sr-announcements');
            announcer.tabIndex = '0';
          } else {
            // Create the div element
            announcer = document.createElement('div');
            announcer.id = 'sr-announcements';
            announcer.tabIndex = '0';
            announcer.setAttribute('aria-live', 'polite');
            announcer.setAttribute('aria-atomic', 'true');

            announcer.style.position = 'absolute';
            announcer.style.width = '0px';
            announcer.style.height = '0px';
            announcer.style.padding = '0';
            announcer.style.overflow = 'hidden';
            announcer.style.whiteSpace = 'nowrap';
            announcer.style.border = '0';

            document.body.insertBefore(announcer, document.body.firstChild);
          }
          announcer.textContent = message;
          announcer.focus();

          setTimeout(() => {
            if (announcer && announcer.parentNode) {
                  announcer.parentNode.removeChild(announcer);
                }
                }, 10000);

          return announcer;
        }

//use showScreenReaderAnnouncer
tp.pianoId.init({
              loginSuccess:(data)=> {
                showScreenReaderAnnouncer(`Login success with ${data.user.email}`);
              }
            });

For questions or implementation support, please contact our Support team at support@piano.io.

Accessibility Update Summary by Release Date

Platform Area

Impact Summary

Client Action Required

Release Date

General – Test-Hook Attribute Guidance

Prevents breakage in automated tests when templates change

Review current use and update test hooks

Released

Identity Management – Keyboard Navigation & Screen Reader Support
(Layout, My Account, Concurrent Sessions, Newsletter)

Tab navigation, modal escape, ARIA roles

No action needed for default templates

Released

Checkout (Subscription Management + Billing Templates)

Contrast for fonts, buttons, text and background has been improved

No action needed

Released

My Account Templates (Subscription Management + Billing)

Contrast for fonts, buttons, text and background has been improved

No action needed

Released

Identity Management – Styling Updates
(Focus outlines, contrast, color)

Visual accessibility improvements

Manual updates or revert to default

Released

Boilerplates
(Fonts, colors, and styles for better readability)

New accessible boilerplates available

Rebuild templates using updated boilerplates

Released

Checkout (Subscription Management + Billing Templates)

Keyboard navigation, ARIA tags, screen reader and modal support

Manual updates required for customized templates

Released

Checkout (Subscription Management + Billing Templates)

Fonts adaptation to the specific browser or operational system settings using em approach instead of pxl

No actions from clients needed

Released

My Account Templates (Subscription Management + Billing)

Keyboard navigation, labels for assistive technologies

Strongly recommended to revert to default, then re-customize

Released

Email Templates

Improvements in accessibility, keyboard navigation, and visual contrast

Default layouts need to be duplicated to use; Manually update for customized templates

Released

Payment Components

Supported providers:

  • Stripe Elements / Cards

  • PayPal (New)

  • Braintree

  • Zlick

  • Cybersource CC

  • GoCardless

  • Datatrans Twint/Cards/GP/AP;

Others under review

Confirm accessibility support with your AM/ payment provider

Released

Piano Templates – Loading Sound Indicator

To enhance accessibility, screen readers provide audio feedback when a template is loading, complementing the visual loading spinner. (nice to have, not mandatory)

No action needed

Released

Identity Management Templates Styling Updates

These updates deliver key accessibility and usability improvements across multiple Identity Management templates, with a focus on enhancing keyboard navigation, screen reader compatibility, and overall user experience.

The comparison below outlines the specific code and structural updates made to each template.

Identity Management Layout

CSS

Before

After

.sub-lead,
.agreement {
  ...
  color: rgba(15, 15, 21, 0.5);
  ...
}
.sub-lead,
.agreement {
  ...
  color: #565656;
  ...
}
.custom-field-type-number .arrow-increment:hover,
.custom-field-type-number .arrow-decrement:hover {
  opacity: 1;
}
.custom-field-type-number .arrow-increment:hover,
.custom-field-type-number .arrow-decrement:hover,
.custom-field-type-number .arrow-increment:focus-within,
.custom-field-type-number .arrow-decrement:focus-within {
  opacity: 1;
}
.input.focused,
.input:focus,
input[type='text']:focus,
input[type='number']:focus,
input[type='date']:focus,
input[type='password']:focus,
input[type='tel']:focus {
  border-color: rgba(15, 15, 21, 0.3);
}
.input.focused:not(.focus-visible),
.input:focus:not(.focus-visible),
input[type='text']:focus:not(.focus-visible),
input[type='number']:focus:not(.focus-visible),
input[type='date']:focus:not(.focus-visible),
input[type='password']:focus:not(.focus-visible),
input[type='tel']:focus:not(.focus-visible) {
  border-color: rgba(15, 15, 21, 0.3);
}

.input.focus-visible,
input[type='text'].focus-visible,
input[type='number'].focus-visible,
input[type='date'].focus-visible,
input[type='password'].focus-visible,
input[type='tel'].focus-visible {
  border-color: #3b67b2;
}
.custom-field .float:hover {
  opacity: 1;
}
.custom-field.custom-field-type-boolean .float {
  top: 3px;
}

.custom-field .float:hover {
  opacity: 1;
}

.custom-field .float:focus-within {
  opacity: 1;
}

.custom-field .float .icon-tooltip:focus-visible {
  border-radius: 4px;
  outline: 1px solid #3b67b2;
  outline-offset: 2px;
}
.input-group .float:hover {
  opacity: 1;
}
.input-group .float:hover,
.input-group .float:focus-within {
  opacity: 1;
}

.input-group .float .icon:focus-visible {
  border-radius: 4px;
  outline: 1px solid #3b67b2;
  outline-offset: 2px;
}
a,
.link {
  color: #3b67b2;
  letter-spacing: 0.01em;
  text-decoration: none;
  cursor: pointer;
}

a:active,
a:hover,
.link:active,
.link:hover {
  color: #345a9a;
}
a,
.link {
  color: #3b67b2;
  letter-spacing: 0.01em;
  text-decoration: none;
  cursor: pointer;
}

a:active,
a:hover,
.link:active,
.link:hover {
  color: #345a9a;
}

a:focus-visible {
  outline: 1px solid #3B67B2;
  outline-offset: 2px;
  border-radius: 4px;
}
label > * {
  vertical-align: middle;
}
label > * {
  vertical-align: middle;
}

label:has(:focus-visible) {
  border-radius: 4px;
  outline: 1px solid #3b67b2;
  outline-offset: 2px;
}
.social-buttons-wrapper {
  margin-top: 0;
  margin-bottom: 24px;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  width: 100%;
  font-size: 0;
  letter-spacing: 0;
  word-spacing: 0;
}
.social-buttons-wrapper {
  margin-top: 0;
  margin-bottom: 24px;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  width: 100%;
  font-size: 0;
  letter-spacing: 0;
  word-spacing: 0;
}

.social-buttons-wrapper button:focus-visible {
  outline: 1px solid #3B67B2;
}

.social-buttons-wrapper 
.branded-social-button:focus-visible {
  outline: 1px solid #3B67B2;
  outline-offset: 2px;
}
.pn-icon {
  width: 12px;
  height: 12px;
  background-repeat: no-repeat;
  background-size: contain;
  opacity: 0.3;
}
.pn-icon {
  width: 24px;
  height: 24px;
  background-repeat: no-repeat;
  background-size: 16px;
  opacity: 0.3;
  background-position: center;
}
.pn-dropdown .pn-dropdown__item:not(.pn-dropdown__item--divider),
.pn-dropdown .iti__country {
  height: 48px;
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  align-items: center;
}

.pn-dropdown .pn-dropdown__item.pn-dropdown__item--text,
.pn-dropdown .iti__country {
  padding: 0 16px;
}
.pn-dropdown 
.pn-dropdown__item:not(.pn-dropdown__item--divider),
.pn-dropdown .iti__country {
  height: 48px;
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  align-items: center;
}

/* Part of code is removed */
.pn-dropdown .pn-dropdown__item--active::after,
.pn-dropdown .iti__active::after {
  ...
}
.pn-dropdown .pn-dropdown__item--active::after,
.pn-dropdown .iti__active::after {
  ...
}

.pn-dropdown .pn-dropdown__item--focus-visible {
  outline: 1px solid #3b67b2;
  outline-offset: -1px;
  border-radius: 0;
}
.language.active {
  background-color: #fbfbfb;
}

.language-selector__toggle:focus .language-label::after {
  content: none;
}
.language.active {
  background-color: #fbfbfb;
}

.language.focus-visible {
  outline: 1px solid #3b67b2;
  outline-offset: -1px;
  border-radius: 0;
}

.language-selector__toggle:focus .language-label::after {
  content: none;
}

.language-selector__toggle:focus-visible {
  border-radius: 4px;
  outline: 1px solid #3B67B2;
  outline-offset: 2px;
}

.language-selector__toggle:focus:not(:focus-visible) {
  outline: none;
}
.pnid-phone-number-dropdown-wrapper .pnid-country-list .iti__country:hover {
  background: rgba(0, 0, 0, .05);
}

Removed

.placeholder .pnid-phone-number-flag,
.input-group .pnid-phone-number-flag {
  display: block;
  cursor: pointer;
  pointer-events: auto;
  width: 32px;
  height: 100%;
  background: red;
}
.placeholder .pnid-phone-number-flag,
.input-group .pnid-phone-number-flag {
  display: block;
  cursor: pointer;
  pointer-events: auto;
  width: 32px;
  height: 100%;
}
.btn {
  ...
}
.btn {
  ...
}

.btn:focus-visible {
  outline: 1px solid #3b67b2;
  outline-offset: 2px;
}
.input-group.pnid-phone-number-wrapper .iti__flag-container {
  position: absolute;
  top: 0;
  left: 0;
  height: 48px;
  width: 34px;
  cursor: pointer;
}
.pnid-phone-number-wrapper .iti__flag-container {
  position: absolute;
  top: 0;
  left: 0;
  height: 48px;
  width: 34px;
  cursor: pointer;
}
.pnid-phone-number-wrapper .iti__flag-container {
  margin-left: 46px;
  padding: 0;
  width: 34px;
}

.pnid-phone-number-wrapper .iti__selected-flag {
  padding: 0;
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-content: center;
  outline: none;
}
.pnid-phone-number-wrapper .iti__flag-container {
  margin-left: 46px;
  padding: 0;
  width: 34px;
  display: flex;
  align-items: center;
}

.pnid-phone-number-wrapper .iti__selected-flag {
  padding: 0;
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-content: center;
  outline: none;
  height: 16px;
  border: none;
  background: none;
}

.pnid-phone-number-wrapper 
.iti__selected-flag:focus-visible {
  border-radius: 4px;
  outline: 1px solid #3b67b2;
  outline-offset: 2px;
}
.pnid-country-list {
  position: absolute;
  max-width: 400px;
  left: 0;
  top: 0;
  overflow-y: scroll;
  overflow-x: hidden;
  height: 100%;
}

Removed

Added

.pn-scale-field-input-wrapper:focus-visible 
.pn-scale-field-input 
.pn-scale-thumb-wrapper 
.pn-scale-thumb-focus {
  outline: 1px solid #3b67b2;
  outline-offset: 2px;
}

.pn-go-back-btn:focus-visible i.icon-back {
  border: 1px solid #3b67b2;
  border-radius: 4px;
}

Identity Management profile in My Account

CSS

Before

After

.btn-primary {
  border: none;
  color: white;
  background-position: 0 0;
  text-shadow: -1px #3a7cdb;
  box-shadow: inset 0 -1px 0 rgba(40, 107, 202, 0);
  padding: 1px 18px;
}
.btn-primary {
  border: none;
  color: white;
  background-position: 0 0;
  text-shadow: -1px #3b67b2;
  box-shadow: inset 0 -1px 0 rgba(40, 107, 202, 0);
  padding: 1px 18px;
}
.btn-link,
.btn-link:active,
.btn-link[disabled] {
  background-color: transparent;
  background-image: none;
  box-shadow: none;
  font-size: 13px;
}

.btn-link {
  color: #428BCA;
  cursor: pointer;
  border-color: transparent;
  border-radius: 0;
}

.btn-link:hover,
.btn-link:focus {
  color: #428BCA;
  text-decoration: none;
  background-color: transparent;
}
.btn-link,
.btn-link:active,
.btn-link[disabled] {
  background-color: transparent;
  background-image: none;
  box-shadow: none;
  font-size: 13px;
  line-height: 16px;
  margin-top: 12px;
}

.btn-link {
  color: #3b67b2;
  cursor: pointer;
  border-color: transparent;
  border-radius: 0;
}

.btn-link:hover,
.btn-link:focus {
  color: #3b67b2;
  text-decoration: none;
  background-color: transparent;
}

.btn-link:focus-visible {
  outline: 1px solid #345a9a;
  outline-offset: 2px;
  border-radius: 4px;
}
input[type='search']::-webkit-search-decoration,
input[type='search']::-webkit-search-cancel-button {
  -webkit-appearance: none;
}
input[type='search']::-webkit-search-decoration,
input[type='search']::-webkit-search-cancel-button {
  -webkit-appearance: none;
}

input[type='checkbox'] {
  appearance: none;
  -webkit-appearance: none;
  width: 12px;
  height: 12px;
  border: 1px solid rgba(0, 0, 0, 0.2);
  border-radius: 1px;
  cursor: pointer;
}

input[type='checkbox']:focus {
  box-shadow: none;
}

input[type='checkbox']:focus-visible {
  outline: 1px solid #3b67b2;
  outline-offset: 2px;
  border: 1px solid rgba(0, 0, 0, 0.2);
}

input[type='checkbox']:checked {
  background: url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTIiIGhlaWdodD0iMTIiIHZ
pZXdCb3g9IjAgMCAxMiAxMiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3Z
nIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik00IDEwTDEgN0w
yIDZMNCA4TDEwIDJMMTEgM0w0IDEwWiIgZmlsbD0iYmxhY2siLz4KPC9zdmc+Cg==") 
  center center no-repeat;
  background-size: 10px;
}
.btn.social.link,
.btn-green {
  color: #ffffff;
  text-shadow: none;
  box-shadow: none;
  border: 0 solid;
  background: none repeat-x scroll 0 0 #81C875;
}
.btn-green {
  color: #ffffff;
  text-shadow: none;
  box-shadow: none;
  border: 0 solid;
  background: none repeat-x scroll 0 0 #81C875;
}
.btn.social:focus,
.btn-green:focus,
.btn.social:hover,
.btn-green:hover {
  color: #ffffff;
  background-color: #74B46A;
}

.btn.social:active,
.btn-green:active {
  color: #ffffff;
  background-color: #74B46A;
}

.btn.social:disabled,
.btn-green[disabled],
.btn-green:disabled {
  text-shadow: none;
  background-color: #CDE9C8;
}

.btn.social:disabled:hover,
.btn-green[disabled]:hover,
.btn-green:disabled:hover {
  text-shadow: none;
  background-color: #CDE9C8;
}
.btn-green:focus,
.btn-green:hover {
  color: #ffffff;
  background-color: #74B46A;
}

.btn:focus-visible {
  outline: 1px solid #3b67b2;
  outline-offset: 2px;
}

.btn-green:active {
  color: #ffffff;
  background-color: #74B46A;
}

.btn-green[disabled],
.btn-green:disabled {
  text-shadow: none;
  background-color: #CDE9C8;
}

.btn.social,
.btn.social.link,
.btn.btn-primary {
  color: white;
  background-color: #3b67b2
}

.btn.social:active,
.btn.social:hover,
.btn.social:focus,
.btn.btn-primary:active,
.btn.btn-primary:hover,
.btn.btn-primary:focus {
  background-color: #2f4e8d;
}

.btn.social.link[disabled],
.btn.btn-primary[disabled] {
  text-shadow: none;
  background-color: #82a1d7;
}

.btn-green[disabled]:hover,
.btn-green:disabled:hover {
  text-shadow: none;
  background-color: #CDE9C8;
}
.input[tabindex='0']:focus,
input[type='text']:focus,
input[type='password']:focus,
input[type='number']:focus,
input[type='tel']:focus,
.input[tabindex='0']:hover,
input[type='text']:hover,
input[type='password']:hover,
input[type='number']:hover,
input[type='tel']:hover{
  border: 1px solid #428BCA;
  box-shadow: none;
  outline: 0;
}
.input[tabindex='0']:focus:not(.focus-visible),
input[type='text']:focus:not(.focus-visible),
input[type='password']:focus:not(.focus-visible),
input[type='number']:focus:not(.focus-visible),
input[type='tel']:focus:not(.focus-visible) {
  border-color: rgba(15, 15, 21, 0.3);
}

.input[tabindex='0'].focus-visible,
input[type='text'].focus-visible,
input[type='password'].focus-visible,
input[type='number'].focus-visible,
input[type='tel'].focus-visible {
  border: 1px solid #3b67b2;
  box-shadow: none;
  outline: 0;
}
textarea:focus {
  outline: none;
  box-shadow: none;
  border: 1px solid #428BCA;
}
textarea:focus {
  outline: none;
  box-shadow: none;
  border: 1px solid #3b67b2;
}
a:hover {
  color: #40526a;
}
a:hover {
  color: #40526a;
}

a:focus-visible {
  outline: 1px solid #345a9a;
  outline-offset: 2px;
  border-radius: 4px;
}

Added

.delete-account-confirmation-close 
.delete-account-confirmation-close-btn:focus-visible,
.pn-phone-confirmation .pn-phone-confirmation-close 
.pn-phone-confirmation-close-btn:focus-visible {
  outline: 1px solid #3b67b2;
  outline-offset: 2px;
  border-radius: 4px;
  opacity: 1;
}
.content-padding-tb {
  clear: both;
  padding: 24px 0;
  max-width: 580px;
}
.content-padding-tb {
  clear: both;
  padding: 24px 10px;
  max-width: 580px;
}
.pn-dropdown .pn-dropdown__item--active::after {
  ...
}
.pn-dropdown .pn-dropdown__item--active::after {
  ...
}

.pn-dropdown .pn-dropdown__item--focus-visible {
  outline: 1px solid #3b67b2;
  outline-offset: -1px;
  border-radius: 0;
}
.pn-icon-tooltip:hover {
  opacity: 0.6;
}
.pn-icon-tooltip:hover {
  opacity: 0.6;
}

.pn-icon-tooltip:focus-visible {
  outline: 1px solid #3b67b2;
  outline-offset: 2px;
  border-radius: 4px;
  opacity: .6;
}
.pnid-phone-number-wrapper .iti__flag-container {
  width: 32px;
  padding: 0;
  margin-left: 8px;
  margin-right: 8px;
}
.pnid-phone-number-wrapper .iti__flag-container {
  min-height: 40px;
  width: 32px;
  padding: 0;
  margin-left: 8px;
  margin-right: 8px;
  display: flex;
  align-items: center;
}
.pnid-phone-number-wrapper .iti__selected-flag {
  padding: 0;
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-content: center;
  outline: none;
}
.pnid-phone-number-wrapper 
.iti__selected-flag {
  padding: 0;
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-content: center;
  outline: none;
  border: none;
  background: transparent;
  height: 16px;
}

.pnid-phone-number-wrapper 
.iti__selected-flag:focus-visible {
  outline: 1px solid #345a9a;
  outline-offset: 2px;
  border-radius: 4px;
}
.pnid-phone-number-focused ::before {
  opacity: 1;
}
.pnid-country-list {
  position: absolute;
  max-width: 400px;
  left: 0;
  top: 0;
  overflow-y: scroll;
  overflow-x: hidden;
  height: auto;
}
.pnid-phone-number-focused ::before {
  opacity: 1;
}
.pn-scale-custom-field-label {
  ...
}

.pn-scale-field-dividers::before {
  background: rgb(66, 139, 202);
}
.pn-scale-custom-field-label {
  ...
}

.pn-scale-field-input-wrapper:focus-visible 
.pn-scale-field-input .pn-scale-thumb-wrapper 
.pn-scale-thumb-focus {
  outline: 1px solid #3b67b2;
  outline-offset: 2px;
}

.pn-scale-field-dividers::before {
  background: #3b67b2;
}

Identity Management Concurrent Sessions

All btn-green classes were replaced by btn-primary in the HTML code of this template.

CSS

Before

After

.cs-myaccount .btn-primary:hover {
  background-color: #74b46a;
}
.cs-myaccount .btn-primary:active,
.cs-myaccount .btn-primary:focus,
.cs-myaccount .btn-primary:hover {
  background-color: #2f4e8d;
}

.cs-myaccount .btn:focus-visible {
  outline: 1px solid #3b67b2;
  outline-offset: 2px;
}
.cs-myaccount .btn-primary {
  color: #ffffff;
  text-shadow: none;
  box-shadow: none;
  border: 0 solid;
  background: none repeat-x scroll 0 0 #81C875;
}
.cs-checkout .btn-primary {
  color: #3b67b2;
}

.cs-checkout .btn:focus-visible {
  outline: 1px solid #3b67b2;
  outline-offset: 2px;
}

Added

.cs-myaccount .cs-session-notification 
.cs-session-notification-action:focus-visible,
.cs-checkout .cs-session-notification 
.cs-session-notification-action:focus-visible {
  border-radius: 4px;
  outline-offset: 2px;
}

.cs-myaccount .cs-session-notification 
.cs-session-notification-action:focus-visible {
  outline: 1px solid white;
}
.cs-checkout .cs-session-notification 
.cs-session-notification-action:focus-visible {
  outline: 1px solid #3b67b2;
}
.cs-header-layout,
.cs-content-item-layout {
  display: grid;
  grid-template-columns: 20px 1fr 20px;
  align-items: center;
  gap: 10px
}
.cs-header-layout,
.cs-content-item-layout {
  display: grid;
  grid-template-columns: 20px 1fr 20px;
  align-items: center;
  gap: 10px;
  padding: 0 10px;
}
.cs-myaccount .cs-footer {
  height: 100px;
  display: flex;
  align-items: center;
  border-top: 1px solid rgba(0, 0, 0, 0.1);
}
.cs-myaccount .cs-footer {
  height: 100px;
  display: flex;
  align-items: center;
  border-top: 1px solid rgba(0, 0, 0, 0.1);
  padding: 0 10px;
}
input[type='checkbox']:disabled {
  background-color: rgba(237, 237, 237, 1);
  cursor: default;
}
input[type='checkbox']:disabled {
  background-color: rgba(237, 237, 237, 1);
  cursor: default;
}

input[type='checkbox']:focus {
  box-shadow: none;
}

input[type='checkbox']:focus-visible {
  outline: 1px solid #3b67b2;
  outline-offset: 2px;
  border: 1px solid rgba(0, 0, 0, 0.2);
}

.pn-icon {
  width: 12px;
  height: 12px;
  background-repeat: no-repeat;
  background-size: contain;
}
.pn-icon-tooltip {
  ...
}
.pn-icon-tooltip {
  ...
}

.pn-icon-tooltip:focus-visible {
  outline: 1px solid #3b67b2;
  outline-offset: 2px;
  border-radius: 4px;
  opacity: 1;
}

Identity Management Newsletters

All btn-green classes were replaced by btn-primary in the HTML code of this template.

Piano Offer Templates Boilerplates Styling Updates

As a default strategy, we recommend creating new templates from boilerplates that already include all accessibility improvements. We also, in most cases, recommend reverting your templates to default versions and then applying custom styling once again. But if your templates are significantly customized, you can use these guidelines and recommendations to understand what was improved in the default versions and improve your templates' accessibility accordingly.

Enhanced Large Font Support

What's changed: We've updated the default boilerplates by converting font-size and line-height properties from fixed values to relative units.

Benefits for users:

  • Automatic adaptation to system font size settings

  • Improved readability for users with visual impairments

  • Proper display when using large system fonts

  • Better compliance with web accessibility standards

Note: This change ensures that the interface respects browser and operating system font preferences, providing a more comfortable reading experience.

Examples:

Before

After

p {
     font-size: 16px;
     line-height: 32px;
}
p {
     font-size: 1rem;
     line-height: 2;
}

Semantic HTML Tags Implementation

What's changed: Replaced generic HTML tags with semantic elements in boilerplate templates.

Benefits for users:

  • Enhanced navigation with screen readers

  • Better content structure recognition by assistive technologies

  • Improved accessibility for users with disabilities

  • Better SEO and machine readability

Note: These changes make templates more accessible and user-friendly, especially for people using assistive technologies to browse the web.

Examples:

Before

After

HTML
<div><button>go back</button>
</div> <span>My Title</span>
<div>Offer information</div>
HTML
<header><button type="button">go back</button></header>
<h2>My Title</h2>
<section>Offer information</section>

High-Contrast Font Update

What's changed: We've replaced fonts in boilerplates with higher contrast alternatives for improved readability.

Improvements:

  • Increased contrast ratio between text and background

  • Enhanced readability across different devices and screen types

Benefits for users:

  • Reduced eye strain during extended reading

  • Better text visibility for users with low vision

  • Compliance with WCAG accessibility standards

Contrast Standard: According to WCAG guidelines, the contrast ratio should be at least 4.5:1 for normal text

How to check contrast yourself: You can verify contrast levels on any website using a Chrome extension (https://chromewebstore.google.com/detail/wcag-color-contrast-check/plnahcmalebffmaghcpcmpaciebdhgdf)

Examples:

Before

After

p {
     color: rgba(54, 54, 54, 0.6)
     /* around 3.71 contrast ratio on white background */
}
p {
     color: rgba(15, 15, 21, 0.6)
     /* around 5 contrast ratio on white background */
}

Enhanced Keyboard Navigation

What's changed: We've verified and ensured that all buttons in the interface are fully accessible and navigable using keyboard controls.

Implemented improvements:

  • All buttons can now be activated using the Tab, Enter, and Spacebar keys

  • Added visible focus indicators for the current element

  • Logical tab order throughout the interface

Benefits for users:

  • Complete interface control without mouse dependency

  • Accessibility for users with mobility limitations

  • Compatibility with assistive technologies

  • Full compliance with web accessibility standards

Key navigation controls:

  • Tab - move to the next element

  • Shift + Tab - move to the previous element

  • Enter or Spacebar - activate button

Testing: You can test keyboard navigation on any page by using the Tab key to move through all interactive elements. Each button should be clearly highlighted when focused and respond to Enter/Spacebar activation.

Examples:

HTML
<button type="button">My button</button>
<a href="#">My link</a>
.my-button:focus-visible,
.my-link:focus-visible {
outline: 1px solid rgba(59, 103, 178, 1);
outline-offset: 2px;
}

Alternative Text for Images

What's changed: All images in boilerplates now include alt attributes with descriptive text.

What is alt text: Alternative text (alt) is a brief description of an image that displays when the image fails to load or is read aloud by screen-reading software.

Benefits for users:

  • Image content understanding for users with visual impairments

  • Image descriptions during slow internet connections

  • Content accessibility through screen readers

  • Improved search engine content indexing

  • Full compliance with WCAG accessibility standards

Note: Alt texts are concise yet descriptive, providing essential information without being overly verbose. Decorative images use empty alt attributes to avoid unnecessary screen reader announcements.

Examples:

HTML
<img src="https://....." alt="My awesome product"/> 
<svg role="img" alt="My awesome product"></svg>

ARIA Attributes Added for Enhanced Accessibility

What's changed: We've implemented ARIA tags (Accessible Rich Internet Applications) throughout our templates to provide detailed descriptions of interface elements.

What are ARIA attributes: ARIA tags are special HTML attributes that provide additional information about element functions and states to assistive technologies.

Implemented ARIA attributes:

  • aria-label — element description for screen readers

  • aria-describedby — connection to additional descriptions

  • aria-expanded — state of collapsible elements

  • aria-hidden — hiding decorative elements from screen readers

  • role — defining element's interface role

Benefits for users:

  • More precise screen reader navigation

  • Clear descriptions of complex interactive elements

  • Element state information (open/closed, active/inactive)

  • Full accessibility standards compliance

  • Enhanced user experience with assistive technologies

Note: These ARIA attributes create a more inclusive web experience by providing rich context and functionality information to users of assistive technologies.

Examples:

aria-label provides an element description when visible text is insufficient or missing.

HTML
<button type="button" aria-label="Close">
<svg>Icon</svg>
</button>
<section aria-label="Offer 1"><div>Offer card</div></section>

aria-describedby connects an element to additional descriptive text located elsewhere.

HTML
<input type="password" aria-describedby="pwd-help">
<div id="pwd-help">Password must contain at least 8 characters</div>
<button aria-describedby="save-desc">Save</button>
<div id="save-desc">Saves changes to the document</div>

aria-expanded indicates whether a collapsible element is open or closed.

HTML
<button aria-expanded="false" aria-controls="menu">Menu</button>
<ul id="menu"></ul>
<details> <summary aria-expanded="true">Details</summary>  </details>

aria-hidden hides decorative elements from screen readers.

HTML
<button> Save <svg aria-hidden="true"></svg> </button>
<div aria-hidden="true"></div>
<span aria-hidden="true"></span> Like

The role attribute tells screen readers what function an element serves in the interface, helping users better understand page structure and navigation.

<div role="search">
<div role="navigation">
<div role="main">
<div role="complementary">
<button role="tab">
<div role="tabpanel">
<div role="alert">
<div role="dialog">
<div role="banner">
<div role="contentinfo">










Piano My Account Styling Updates

As a default strategy, we recommend reverting your templates to default versions and then applying custom styling once again. But if your templates are significantly customized, you can use these guidelines and recommendations to understand what was improved in the default versions and improve your templates' accessibility accordingly.

Improved semantics of HTML elements

What was changed: We updated the My Account HTML templates according to WCAG, changed tags from <a> or <div> to <button>.

Benefits for users:

  • Better user experience of interactive elements (buttons, dropdowns, form elements) in user interfaces

  • Improved user experience for assistive technologies like VoiceOver, NVDA

  • Better user experience with keyboard navigation

Examples:

Before

After

HTML
<a href="#" ng-show="canResendReceipt" 
ng-click="resendReceipt(event)"</pre>
<pre>class="icon-mail myaccount-action-icon" 
title="Send Email"></a>
HTML
<button ng-show="canResendReceipt" ng-click="resendReceipt(event)"  
title="{{ 'Send Email' | tc:'checkout.platform' }}" 
type="button" aria-label="{{ 'Send Email' | tc:'checkout.platform' }}"
> <span></span> </button>
HTML
<div ng-
click="addNewAccount()" data-e2e="paypal-express-
checkout-login-button"></div>
HTML
<button aria-label="{{ 'Log in with PayPal' | tc:'checkout.platform' }}"
type="button" 
ng-click="addNewAccount()" data-e2e="paypal-express-checkout-login-button"></button>

Enhanced keyboard navigation

What was changed: Added the possibility to navigate over elements by keyboard.

Benefits to users:

  • Interface became accessible for users with disabilities and more responsive for all users who interact with the keyboard

  • Faster interaction for experienced users

Examples:

  • Added the possibility to close modal windows with the ‘Esc’ button.

  • Added the possibility to navigate over radio-button options with the arrow keys.

Increased color contrast

What was changed: Changed colors in CSS for the My account interface to meet the desired contrast ratio. This affects the colors of text, background, icons, borders, and outlines.

Benefits to users:

  • More readable text in some scenarios with dimmed screens

  • More distinctive states of user interface elements while they are in focus or have errors

Examples:

Before

After

HTML
<a href="#" ng-
input[type="text"],
input[type="password"] {
...
border: 1px solid #e5e5e5;
...
color: #333333;
}
input[type="text"], input[type="password"] 
{ ... border: 1px solid rgba(15, 15, 21, 0.12); ... color: #0f0f15; }
textarea {
border: 1px solid #e5e5e5;
border-radius: 4px;
}
textarea:focus {
outline: none;
box-shadow: none;
border: 1px solid #e5e5e5;
}
HTML
<button aria-label="{{ 'Log in with PayPal' | tc:'checkout.platform' }}"
type="button" 
ng-click="addNewAccount()" data-e2e="paypal-express-checkout-login-button"></button>
body {
color: #333333;
...
body { color: #0f0f15; ...

Improved Focus Behavior

What was changed: Added automatic focusing after opening modal windows, switching between states of My Account.

Benefits to the user:

  • Better user experience and visibility of the current focused element. Simplified navigation between them.

Examples:

  • Added automatic focus to the text field (textarea) element after opening an inquiry in the Help section

Improved Assistive Technology Support

What was changed: Improved assistive technology support by adding necessary ARIA attributes in HTML templates.

Benefits to the user:

  • Users can now better understand what exactly the element is, what it controls, or what is represented in the image

  • Some elements are hidden from assistive technologies since they are purely cosmetic, which saves time on pronunciation.

  • Added pronunciation of errors, or some user-triggered events like switching the toggle.

Examples:

Before

After

HTML
<div>
HTML
<div role="dialog" aria-modal="true"
aria-labelledby="modal-title"> <h2 id="modal-title" >
{{'Cancel subscription confirmation' | tc:'checkout.platform'}}</h2>
HTML
<div ng-click="close()">x</div>
HTML
<button type="button" ng-click="close()"
aria-label="{{ 'Close' | tc:'checkout.platform' }}">x</button>
HTML
<img ng-src="{{getImageSrc(card)}}" />
HTML
<img ng-src="{{getImageSrc(card)}}" 
alt="{{ 'Payment method logo' | tc:'checkout.platform' }}"/>
HTML
<div ma-error-section
errors="card.formErrors"></div>
HTML
<div ma-error-section errors="card.formErrors"
aria-live="assertive"></div>

The following outlines template-specific accessibility improvements related to payment providers.

My Account Wallet Components

Find <script type="text/ng-template" id="/frontend/providers/components/datatranspaypal/my_account/component.shtml"> and replace this part:

HTML
<div ng-if="!readonly" ng-click="cancelNewAccount()">
  <t>Cancel</t>
</div>

With:

HTML
<button ng-if="!readonly" ng-click="cancelNewAccount()" type="button">
  <t>Cancel</t>
</button>

Find <script type="text/ng-template" id="/frontend/providers/components/datatranstwint/my_account/component.shtml"> and replace this part:

HTML
<div ng-if="!readonly" ng-click="cancelNewAccount()">
  <t>Cancel</t>
</div>

With:

HTML
<button type="button" ng-if="!readonly" ng-click="cancelNewAccount()">
  <t>Cancel</t>
</button>

Find <script type="text/ng-template" id="/frontend/providers/components/gocardlessdropin/my_account/component.shtml"> and replace this part:

HTML
<div ng-click="cancelNewMandate()">
  <t>Cancel</t>
</div>

With:

HTML
<button type="button" ng-click="cancelNewMandate()">
  <t>Cancel</t>
</button>

In the same component, replace this part:

HTML
<button ng-click="addNewMandate()"
  ng-disabled="!isLoaded"
 >

With:

HTML
<button ng-click="addNewMandate()"
  ng-disabled="!isLoaded"
 
  type="button">

My Account Help Components

Find <script type="text/ng-template" id="/widget/myaccount/partials/help/list.shtml"> and replace this part:

HTML
<div>
    <div ng-show="inquires.length == 0  && !isLoading">
        <h2><t>Having an issue?</t></h2>
        <div><t>Create an inquiry here, and we'll make sure your questions get answered ASAP.</t></div>
    </div>
    <span ng-show="inquires.length > 0"><t>Inquiries</t> ({{inquires.length}})</span>
    <button type="button" ng-show="!isLoading" ng-click="createInquiry()"><t>Get help!</t></button>

With:

HTML
<div>
    <div ng-show="inquires.length == 0  && !isLoading">
        <h2><t>Having an issue?</t></h2>
        <div><t>Create an inquiry here, and we'll make sure your questions get answered ASAP.</t></div>
    </div>
    <span ng-show="inquires.length > 0"><t>Inquiries</t> ({{inquires.length}})</span>
    <button type="button" ng-show="!isLoading" ng-click="createInquiry()"><t>Get help!</t></button>

My Account Library Components

Find <script type="text/ng-template" id="/widget/myaccount/partials/library/_library_item_cancel_confirm.shtml"> and remove this line:

HTML
<button type="button" ng-click="close()" aria-label="{{'Close' | tc:'checkout.platform'}}"></button>

In the same section, find this part:

HTML
<div>
  <button type="button" ng-click="confirm()"><t context="checkout.platform">Yes</t></button>
  <button type="button" ng-click="close()"><t context="checkout.platform">No</t></button>
</div>

And replace with:

HTML
<div>
  <button type="button" ng-click="confirm()"><t context="checkout.platform">Yes</t></button>
  <button type="button" ng-click="close()"><t context="checkout.platform">No</t></button>
</div>
<button type="button" ng-click="close()" aria-label="{{'Close' | tc:'checkout.platform'}}"></button>

Find <script type="text/ng-template" id="/widget/myaccount/partials/library/_library_item_renew_confirm.shtml"> and remove this line:

HTML
<button type="button" ng-click="close()" aria-label="{{'Close' | tc:'checkout.platform'}}"></button>

In the same section, find this part:

HTML
<div>
  <button type="button" ng-click="confirm()">
    <t context="checkout.platform">Yes</t>
  </button>
  <button type="button" ng-click="close()">
    <t context="checkout.platform">No</t>
  </button>
</div>

And replace with:

HTML
<div>
  <button type="button" ng-click="confirm()">
    <t context="checkout.platform">Yes</t>
  </button>
  <button type="button" ng-click="close()">
    <t context="checkout.platform">No</t>
  </button>
</div>
<button type="button" ng-click="close()" aria-label="{{'Close' | tc:'checkout.platform'}}"></button>

Find <script type="text/ng-template" id="/widget/myaccount/partials/library/_library_item_deferred_cancel_confirm.shtml"> and remove this line:

HTML
<button type="button" ng-click="close()" aria-label="{{'Close' | tc:'checkout.platform'}}"></button>

In the same section, find this part:

HTML
<div>
  <button type="button" ng-click="confirm()"><t context="checkout.platform">Yes</t></button>
  <button type="button" ng-click="close()"><t context="checkout.platform">No</t></button>
</div>

And replace with:

HTML
<div>
  <button type="button" ng-click="confirm()"><t context="checkout.platform">Yes</t></button>
  <button type="button" ng-click="close()"><t context="checkout.platform">No</t></button>
</div>
<button type="button" ng-click="close()" aria-label="{{'Close' | tc:'checkout.platform'}}"></button>

Find <script type="text/ng-template" id="/widget/myaccount/partials/library/_library_item_refund_confirm.shtml"> and remove this line:

HTML
<button type="button" ng-click="close()" aria-label="{{'Close' | tc:'checkout.platform'}}"></button>

In the same section, find this part:

HTML
<div>
  <button type="button" ng-click="confirm()"><t context="checkout.platform">Yes</t></button>
  <button type="button" ng-click="close()"><t context="checkout.platform">No</t></button>
</div>

And replace with:

HTML
<div>
  <button type="button" ng-click="confirm()"><t context="checkout.platform">Yes</t></button>
  <button type="button" ng-click="close()"><t context="checkout.platform">No</t></button>
</div>
<button type="button" ng-click="close()" aria-label="{{'Close' | tc:'checkout.platform'}}"></button>

Find <script type="text/ng-template" id="/widget/myaccount/partials/library/_library_update_payment_method.shtml"> and remove this line:

HTML
<button type="button" ng-click="close()" aria-label="{{ 'Close' | tc:'checkout.platform' }}">x</button>

In the same section, find this part:

HTML
  <div ng-show="card.showButtons">
    <div>
      <button type="button" data-e2e="save-card" ng-click="save()" ng-disabled="isSaveButtonDisabled">
        <t context="checkout.platform">Add</t>
      </button>
    </div>
  </div>
</div>

And replace with:

HTML
  <div ng-show="card.showButtons">
    <div>
      <button type="button" data-e2e="save-card" ng-click="save()" ng-disabled="isSaveButtonDisabled">
        <t context="checkout.platform">Add</t>
      </button>
    </div>
  </div>
</div>
<button type="button" ng-click="close()" aria-label="{{ 'Close' | tc:'checkout.platform' }}">x</button>

Find <script type="text/ng-template" id="/widget/myaccount/partials/library/_library_item_leave_shared_subscription_confirm.shtml"> and remove this line:

HTML
<button type="button" ng-click="close()" aria-label="{{'Close' | tc:'checkout.platform'}}"></button>

In the same section, find this part:

HTML
<div>
    <button type="button" ng-click="confirm()"><t context="checkout.platform">Yes</t></button>
    <button type="button" ng-click="close()"><t context="checkout.platform">No</t></button>
</div>

And replace with:

HTML
<div>
    <button type="button" ng-click="confirm()"><t context="checkout.platform">Yes</t></button>
    <button type="button" ng-click="close()"><t context="checkout.platform">No</t></button>
</div>
<button type="button" ng-click="close()" aria-label="{{'Close' | tc:'checkout.platform'}}"></button>

Find <script type="text/ng-template" id="/widget/myaccount/partials/library/terminate-pianoid-sessions-confirmation.shtml"> and remove this line:

HTML
<button type="button" ng-click="close()" aria-label="{{'Close' | tc:'checkout.platform'}}"></button>

In the same section, find this part:

HTML
<div>
    <button type="button" ng-click="confirm()"><t context="checkout.platform">Terminate</t></button>
    <button type="button" ng-click="close()"><t context="checkout.platform">Cancel</t></button>
</div>

And replace with:

HTML
<div>
    <button type="button" ng-click="confirm()"><t context="checkout.platform">Terminate</t></button>
    <button type="button" ng-click="close()"><t context="checkout.platform">Cancel</t></button>
</div>
<button type="button" ng-click="close()" aria-label="{{'Close' | tc:'checkout.platform'}}"></button>

My Account Licensing Components

Find <script type="text/ng-template" id="/widget/myaccount/partials/licensing/restore-contract-user.shtml"> and replace this part:

HTML
  <a href="#" ng-click="restore()">
    <t>Restore</t>
  </a>
</div>

With:

HTML
  <a href="#" ng-click="restore()">
    <t>Restore</t>
  </a>
</div>
<div tabindex="0"></div>

Find <script type="text/ng-template" id="/widget/myaccount/partials/licensing/invite-contract-user.shtml"> and replace this part:

HTML
  <a
     href="#"
     data-e2e-modal-action="send"
     ng-click="send()">
    <t>Send</t>
  </a>
</div>

With:

HTML
  <a
     href="#"
     data-e2e-modal-action="send"
     ng-click="send()">
    <t>Send</t>
  </a>
</div>
<div tabindex="0"></div>

Find <script type="text/ng-template" id="/widget/myaccount/partials/licensing/revoke-remove-contract-domain.shtml"> and replace this part:

HTML
  <a href="#"
     ng-click="revokeAndRemove()"
     data-e2e-modal-action="revoke_and_remove">
    <t>Revoke and remove</t>
  </a>
</div>

With:

HTML
  <a href="#"
     ng-click="revokeAndRemove()"
     data-e2e-modal-action="revoke_and_remove">
    <t>Revoke and remove</t>
  </a>
</div>
<div tabindex="0"></div>

Find <script type="text/ng-template" id="/widget/myaccount/partials/licensing/revoke-remove-contract-user.shtml"> and replace this part:

HTML
  <a href="#"
     data-e2e-modal-action="revoke_and_remove"
     ng-click="revokeAndRemove()">
    <t>Revoke and remove</t>
  </a>
</div>

With:

HTML
  <a href="#"
     data-e2e-modal-action="revoke_and_remove"
     ng-click="revokeAndRemove()">
    <t>Revoke and remove</t>
  </a>
</div>
<div tabindex="0"></div>

My Account Voucher Components

Find <script type="text/ng-template" id="/widget/myaccount/partials/voucher/_voucher_item_refund_confirm.shtml"> and remove this line:

HTML
<button type="button" ng-click="close()" aria-label="{{'Close' | tc:'checkout.platform'}}"></button>

In the same section, find this part:

HTML
<div>
    <button type="button" ng-click="confirm()"><t context="checkout.platform">Yes</t></button>
    <button type="button" ng-click="close()"><t context="checkout.platform">No</t></button>
</div>

And replace with:

HTML
<div>
    <button type="button" ng-click="confirm()"><t context="checkout.platform">Yes</t></button>
    <button type="button" ng-click="close()"><t context="checkout.platform">No</t></button>
</div>
<div tabindex="0"></div>

My Account Wallet Components

Find <script type="text/ng-template" id="/widget/myaccount/partials/wallet/_wallet_item_remove_confirm.shtml"> and replace this part:

HTML
<div>
    <button type="button" ng-click="confirm()"><t context="checkout.platform">Yes</t></button>
    <button type="button" ng-click="close()"><t context="checkout.platform">No</t></button>
</div>

With:

HTML
<div>
    <button type="button" ng-click="confirm()"><t context="checkout.platform">Yes</t></button>
    <button type="button" ng-click="close()"><t context="checkout.platform">No</t></button>
</div>
<button type="button" ng-click="close()" aria-label="{{'Close' | tc:'checkout.platform'}}"></button>

Find <script type="text/ng-template" id="/widget/myaccount/partials/wallet/wallet_form_datatrans_postfinance.shtml"> and replace this part:

HTML
<div ng-click="addNewAccount()" role="button" tabindex="0" aria-label="{{'Log in with Postfinance' | tc:'checkout.platform'}}"></div>

With:

HTML
<button ng-click="addNewAccount()" type="button" tabindex="0" aria-label="{{'Log in with Postfinance' | tc:'checkout.platform'}}"></button>

Find <script type="text/ng-template" id="/widget/myaccount/partials/wallet/wallet_bank_secure.shtml"> and remove this line:

HTML
<button type="button" ng-click="close()" aria-label="{{'Close' | tc:'checkout.platform'}}"></button>

In the same section, find this part:

HTML
<div role="dialog" aria-modal="true">
    <div id="secure-container-wrapper">
        <div id="secure-container">
        </div>
    </div>
</div>

And replace with:

HTML
<div role="dialog" aria-modal="true">
    <div id="secure-container-wrapper">
        <div id="secure-container">
        </div>
    </div>
</div>
<button type="button" ng-click="close()" aria-label="{{'Close' | tc:'checkout.platform'}}"></button>

Piano Emails Styling Updates

As a default strategy, we recommend creating new versions of email templates from the default one again. But if your templates are significantly customized, you can use these guidelines and recommendations to understand what was improved in the default versions and improve your templates' accessibility accordingly.

Increased color contrast

What was changed: Changed inline styles and styles in the tag <style> for colors right in the email template.

Benefits for users:

  • More readable text in some scenarios with dimmed screens

Examples:

Master layout:


a {
  display: inline-block;
  color: #325ca4;
  text-align: left;
  font-family: 
    "Graphik Pdf Regular",
    "IPAex Gothic",
    "Noto Sans CJK JP Regular",
    Arial,
    sans-serif;

  text-decoration-line: underline;
  text-decoration-style: solid;
  text-decoration-color: rgba(50, 92, 164, 0.2);
  text-decoration-thickness: auto;
  text-decoration-skip-ink: none;
  text-underline-offset: 25%;
  text-underline-position: from-font;
}
HTML
<div ng-click="close()">x</div>

<a
  href="http://piano.io/privacy/"
  style="
    display: inline-block;
    text-decoration: none;
    text-transform: uppercase;
    color: #767a87;
    font-family: 'Graphik Pdf Regular', 
                        'IPAex Gothic', 
                        'Noto Sans CJK JP Regular', 
                         Arial, sans-serif;
    font-size: 9.5px;
    font-weight: normal;
    line-height: 22px;
    padding: 0 17px;
  "
>
  <span style="letter-spacing: 0.075em;">
    <t>Privacy policy</t>
  </span>
</a>
HTML
<a
  aria-label="Go to privacy policy"
  href="http://piano.io/privacy/"
  style="
    display: inline-block;
    color: #325ca4;
    text-decoration-line: underline;
    text-decoration-style: solid;
    text-decoration-skip-ink: none;
    text-decoration-color: rgba(50, 92, 164, 0.20);
    text-decoration-thickness: auto;
    text-underline-offset: 25%;
    text-underline-position: from-font;
    text-transform: uppercase;
    font-size: 9.5px;
    line-height: 12px;
    text-align: left;
    font-family: Graphik Pdf Regular, 
                        IPAex Gothic, 
                        Noto Sans CJK JP Regular, 
                        Arial, sans-serif;
    font-weight: 400;
    padding: 0 10px;
  "
>
  <span><t>Privacy policy</t></span>
</a>

Improved assistive technology support

What was changed: Improved assistive technology support by adding necessary ARIA attributes to email templates.

Benefits to the user:

  • Users can now better understand what exactly the element is

Examples:

Before

After

HTML
<div>
  <a href="{{email_confirmation_url}}" target="_blank">
    Clicking here.
  </a>
</div>
HTML
<a
  aria-label="Go to confirmation"
  href="{{email_confirmation_url}}"
  target="_blank"
  style="
    display: inline-block;
    color: #325ca4;
    text-decoration-line: underline;
    text-decoration-style: solid;
    text-decoration-skip-ink: none;
    text-decoration-color: rgba(50, 92, 164, 0.20);
    text-decoration-thickness: auto;
    text-underline-offset: 25%;
    text-underline-position: from-font;
    text-align: left;
    font-family: Graphik Pdf Regular, 
                       IPAex Gothic, 
                       Noto Sans CJK JP Regular, 
                       Arial, sans-serif;
  "
>
  clicking here.
</a>
HTML
<t>Thanks again, and please drop us a line if
you have any questions: <a
href="mailto:support@piano.io">support@piano.io</a>.</t>
HTML
<t>Thanks again, and please drop us a line if you have any questions: <a 
aria-label="send email to support team" 
href="mailto:support@piano.io">support@piano.io</a>.</t>

Last updated: