Accessibility

Build inclusive interfaces with dynamic ARIA attributes and live regions

Accessibility attributes help you create inclusive web experiences by dynamically updating ARIA attributes and announcing content changes to screen readers.

dbind_aria-*

Purpose: Dynamically bind values to any ARIA attribute, making your dynamic content accessible to assistive technologies.

Syntax:

<element dbind_aria-label="fieldName"></element>
<element dbind_aria-describedby="fieldName"></element>
<element dbind_aria-hidden="fieldName"></element>

Supported ARIA Attributes

DBindly supports binding to any ARIA attribute:

AttributePurposeExample
aria-labelAccessible nameButton labels, icon descriptions
aria-describedbyID of describing elementForm field descriptions
aria-labelledbyID of labeling elementModal titles
aria-hiddenHide from assistive techDecorative elements
aria-expandedExpandable stateAccordions, dropdowns
aria-selectedSelection stateTabs, list items
aria-pressedToggle button stateToggle buttons
aria-checkedCheckbox/radio stateCustom checkboxes
aria-disabledDisabled stateDisabled buttons
aria-busyLoading stateLoading regions
aria-currentCurrent itemNavigation, pagination
aria-valuenowCurrent valueProgress bars, sliders
aria-valueminMinimum valueProgress bars, sliders
aria-valuemaxMaximum valueProgress bars, sliders

dbind_aria-label

Purpose: Provide an accessible name for elements that don't have visible text.

Basic Usage

<!-- Icon button with dynamic label -->
<button dbind_aria-label="deleteLabel" dbind_click="deleteItem">
  <svg><!-- trash icon --></svg>
</button>

Data:

{
  "deleteLabel": "Delete item: Project Alpha"
}

Use Cases

1. Icon Buttons

<div class="action-buttons">
  <button dbind_aria-label="editLabel" class="icon-button">
    <svg><!-- edit icon --></svg>
  </button>
  <button dbind_aria-label="deleteLabel" class="icon-button">
    <svg><!-- delete icon --></svg>
  </button>
  <button dbind_aria-label="shareLabel" class="icon-button">
    <svg><!-- share icon --></svg>
  </button>
</div>

Data:

{
  "editLabel": "Edit document: Annual Report",
  "deleteLabel": "Delete document: Annual Report",
  "shareLabel": "Share document: Annual Report"
}

2. Dynamic Search Input

<input
  type="search"
  dbind_aria-label="searchLabel"
  dbind_placeholder="searchPlaceholder"
>

Data:

{
  "searchLabel": "Search 1,234 products",
  "searchPlaceholder": "Search products..."
}

3. Pagination Controls

<nav aria-label="Pagination">
  <button dbind_aria-label="prevPageLabel" dbind_hide="isFirstPage">
    ← Previous
  </button>
  <button dbind_aria-label="nextPageLabel" dbind_hide="isLastPage">
    Next →
  </button>
</nav>

Data:

{
  "prevPageLabel": "Go to page 2",
  "nextPageLabel": "Go to page 4"
}

4. Product Images in Lists

<div dbind_repeat="products">
  <a dbind_href="url" dbind_aria-label="productLink">
    <img dbind_src="image" alt="">
  </a>
</div>

Data:

{
  "products": [
    {
      "url": "/products/headphones",
      "image": "/images/headphones.jpg",
      "productLink": "View Wireless Headphones, $149.99"
    }
  ]
}

dbind_aria-describedby

Purpose: Link an element to a description, providing additional context for screen reader users.

Basic Usage

<input
  type="password"
  id="password"
  dbind_aria-describedby="passwordHintId"
>
<p id="password-hint" dbind_data="passwordHint"></p>

Use Cases

1. Form Field Descriptions

<div class="form-group">
  <label for="username">Username</label>
  <input
    type="text"
    id="username"
    dbind_model="username"
    aria-describedby="username-hint username-error"
  >
  <p id="username-hint" class="hint">3-20 characters, letters and numbers only</p>
  <p id="username-error" class="error" dbind_error-field="username"></p>
</div>

2. Dynamic Help Text

<div class="form-group">
  <label for="coupon">Coupon Code</label>
  <input
    type="text"
    id="coupon"
    dbind_model="couponCode"
    dbind_aria-describedby="couponHintId"
  >
  <p dbind_data="couponHint" id="coupon-hint"></p>
</div>

Data (changes based on validation):

// Before validation
{ "couponHint": "Enter your coupon code", "couponHintId": "coupon-hint" }
 
// Valid coupon
{ "couponHint": "Coupon applied! 20% off", "couponHintId": "coupon-hint" }
 
// Invalid coupon
{ "couponHint": "Invalid coupon code", "couponHintId": "coupon-hint" }

dbind_aria-hidden

Purpose: Hide decorative or redundant content from assistive technologies.

Basic Usage

<!-- Hide decorative icon -->
<span dbind_aria-hidden="true" class="icon">🎉</span>
<span>Celebration Mode</span>
 
<!-- Dynamically hide/show -->
<div dbind_aria-hidden="isHiddenFromScreenReader">
  <!-- Content -->
</div>

Use Cases

1. Decorative Icons

<button>
  <span aria-hidden="true">🛒</span>
  Add to Cart
</button>

2. Duplicate Information

<div class="product-card">
  <!-- Visual rating stars - hidden from SR -->
  <div class="stars" dbind_aria-hidden="true">★★★★☆</div>
  <!-- Accessible rating text - visible to SR -->
  <span class="sr-only">Rating: 4 out of 5 stars</span>
</div>

3. Loading Content

<div dbind_collection="items">
  <!-- Hide skeleton from screen readers -->
  <div class="skeleton" dbind_loading="show" aria-hidden="true">
    <!-- Skeleton content -->
  </div>
 
  <!-- Main content -->
  <div dbind_loading="hide" dbind_repeat="data">
    <div dbind_data="name"></div>
  </div>
</div>

dbind_aria-expanded

Purpose: Indicate whether a collapsible section is expanded or collapsed.

Basic Usage

<button
  dbind_aria-expanded="isExpanded"
  dbind_click="toggleSection"
  aria-controls="content-section"
>
  <span dbind_hide="isExpanded">Show More</span>
  <span dbind_show="isExpanded">Show Less</span>
</button>
 
<div id="content-section" dbind_show="isExpanded">
  <!-- Expandable content -->
</div>

Use Cases

1. Accordion

<div class="accordion" dbind_repeat="sections">
  <div class="accordion-item">
    <button
      class="accordion-header"
      dbind_aria-expanded="isOpen"
      dbind_click="toggleSection:{{_index}}"
      aria-controls="section-{{_index}}"
    >
      <span dbind_data="title"></span>
      <span class="icon" dbind_aria-hidden="true">
        <span dbind_hide="isOpen">+</span>
        <span dbind_show="isOpen"></span>
      </span>
    </button>
    <div
      class="accordion-content"
      id="section-{{_index}}"
      dbind_show="isOpen"
    >
      <div dbind_html="content"></div>
    </div>
  </div>
</div>

2. Dropdown Menu

<div class="dropdown">
  <button
    class="dropdown-trigger"
    dbind_aria-expanded="isOpen"
    dbind_click="toggleDropdown"
    aria-haspopup="true"
    aria-controls="dropdown-menu"
  >
    Options
    <span dbind_aria-hidden="true"></span>
  </button>
 
  <ul
    id="dropdown-menu"
    class="dropdown-menu"
    dbind_show="isOpen"
    role="menu"
  >
    <li role="menuitem"><a href="#">Edit</a></li>
    <li role="menuitem"><a href="#">Delete</a></li>
    <li role="menuitem"><a href="#">Share</a></li>
  </ul>
</div>

3. Collapsible Card

<div class="collapsible-card">
  <div class="card-header">
    <h3 dbind_data="title"></h3>
    <button
      dbind_aria-expanded="isExpanded"
      dbind_click="toggleCard"
      aria-controls="card-content"
      dbind_aria-label="toggleLabel"
    >
      <span dbind_aria-hidden="true"></span>
    </button>
  </div>
  <div id="card-content" class="card-body" dbind_show="isExpanded">
    <p dbind_data="content"></p>
  </div>
</div>

dbind_aria-selected

Purpose: Indicate selection state for selectable items like tabs or list items.

Basic Usage

<div role="tablist">
  <button
    role="tab"
    dbind_repeat="tabs"
    dbind_aria-selected="isActive"
    dbind_click="selectTab:{{id}}"
  >
    <span dbind_data="label"></span>
  </button>
</div>

Use Cases

1. Tab Navigation

<div class="tabs">
  <div role="tablist" class="tab-list">
    <button
      role="tab"
      id="tab-overview"
      dbind_aria-selected="overviewActive"
      dbind_click="setTab:overview"
      aria-controls="panel-overview"
    >
      Overview
    </button>
    <button
      role="tab"
      id="tab-features"
      dbind_aria-selected="featuresActive"
      dbind_click="setTab:features"
      aria-controls="panel-features"
    >
      Features
    </button>
    <button
      role="tab"
      id="tab-reviews"
      dbind_aria-selected="reviewsActive"
      dbind_click="setTab:reviews"
      aria-controls="panel-reviews"
    >
      Reviews
    </button>
  </div>
 
  <div
    role="tabpanel"
    id="panel-overview"
    aria-labelledby="tab-overview"
    dbind_show="overviewActive"
  >
    <!-- Overview content -->
  </div>
  <div
    role="tabpanel"
    id="panel-features"
    aria-labelledby="tab-features"
    dbind_show="featuresActive"
  >
    <!-- Features content -->
  </div>
  <div
    role="tabpanel"
    id="panel-reviews"
    aria-labelledby="tab-reviews"
    dbind_show="reviewsActive"
  >
    <!-- Reviews content -->
  </div>
</div>

2. Selectable List

<ul role="listbox" class="selectable-list">
  <li
    role="option"
    dbind_repeat="options"
    dbind_aria-selected="isSelected"
    dbind_click="selectOption:{{id}}"
    dbind_class="selectedClass"
  >
    <span dbind_data="label"></span>
  </li>
</ul>

dbind_aria-busy

Purpose: Indicate that a region is being updated and assistive technologies should wait.

Basic Usage

<div
  dbind_aria-busy="isLoading"
  aria-live="polite"
  dbind_collection="items"
>
  <div dbind_repeat="data">
    <span dbind_data="name"></span>
  </div>
</div>

Use Cases

1. Loading Table

<table dbind_aria-busy="isLoading">
  <thead>
    <tr>
      <th>Name</th>
      <th>Status</th>
    </tr>
  </thead>
  <tbody dbind_repeat="data">
    <tr>
      <td dbind_data="name"></td>
      <td dbind_data="status"></td>
    </tr>
  </tbody>
</table>

2. Search Results

<div class="search-container">
  <input type="search" dbind_search="results">
 
  <div
    class="results"
    dbind_aria-busy="isSearching"
    aria-live="polite"
    role="region"
    aria-label="Search results"
  >
    <div dbind_repeat="data" class="result-item">
      <span dbind_data="title"></span>
    </div>
  </div>
</div>

dbind_live

Purpose: Create ARIA live regions that announce dynamic content changes to screen readers.

Syntax:

<element dbind_live="politeness"></element>

Politeness Levels

LevelBehaviorUse For
politeAnnounced when user is idleStatus updates, new content
assertiveAnnounced immediatelyErrors, critical alerts
offNot announcedDisable announcements

Basic Usage

<!-- Polite announcement for status updates -->
<div dbind_live="polite" dbind_data="statusMessage"></div>
 
<!-- Assertive announcement for errors -->
<div dbind_live="assertive" dbind_error></div>

Use Cases

1. Form Validation Errors

<form dbind_submit="/api/register">
  <div class="form-group">
    <label for="email">Email</label>
    <input type="email" id="email" dbind_model="email">
    <!-- Assertive: errors are announced immediately -->
    <span class="error" dbind_live="assertive" dbind_error-field="email"></span>
  </div>
 
  <button type="submit">Register</button>
 
  <!-- General form error -->
  <div class="form-error" dbind_live="assertive" dbind_error></div>
</form>

2. Cart Updates

<div class="cart-summary">
  <!-- Polite: cart updates when user isn't busy -->
  <div dbind_live="polite">
    <span dbind_data="cartItemCount"></span> items in cart
    - Total: <span dbind_data="cartTotal" dbind_format="currency:USD"></span>
  </div>
</div>

3. Search Result Count

<div class="search-results" dbind_collection="searchResults">
  <!-- Announce result count changes -->
  <p dbind_live="polite" class="result-count">
    Found <span dbind_data="totalResults" dbind_format="number"></span> results
  </p>
 
  <div dbind_repeat="data">
    <div class="result-item" dbind_data="title"></div>
  </div>
</div>

4. Notification Toast

<div class="toast-container">
  <div
    class="toast"
    dbind_show="toastVisible"
    dbind_live="polite"
    role="status"
  >
    <span dbind_data="toastMessage"></span>
  </div>
</div>

5. Progress Updates

<div class="upload-progress">
  <progress dbind_data="uploadPercent" max="100"></progress>
  <!-- Announce progress milestones -->
  <span dbind_live="polite">
    <span dbind_data="uploadPercent" dbind_format="percent:0"></span> complete
  </span>
</div>

Progress Bar Accessibility

Accessible Progress Bar

<div
  role="progressbar"
  dbind_aria-valuenow="currentProgress"
  aria-valuemin="0"
  aria-valuemax="100"
  dbind_aria-label="progressLabel"
>
  <div class="progress-fill" style="width: {{currentProgress}}%"></div>
</div>
<span dbind_live="polite" dbind_data="progressStatus"></span>

Data:

{
  "currentProgress": 75,
  "progressLabel": "File upload progress",
  "progressStatus": "75% complete, 2 files remaining"
}

Complete Example: Accessible Product Listing

<main id="main-content">
  <h1>Products</h1>
 
  <!-- Search with accessibility -->
  <div class="search-container" role="search">
    <label for="product-search" class="sr-only">Search products</label>
    <input
      type="search"
      id="product-search"
      dbind_search="products"
      dbind_aria-label="searchLabel"
      dbind_placeholder="searchPlaceholder"
    >
    <span class="search-loading" dbind_loading="show" role="status">
      <span class="sr-only">Searching...</span>
      <div class="spinner" aria-hidden="true"></div>
    </span>
  </div>
 
  <!-- Results region -->
  <div
    class="products-region"
    dbind_collection="products"
    dbind_aria-busy="isLoading"
    aria-label="Product list"
    role="region"
  >
    <!-- Result count announcement -->
    <p class="result-summary" dbind_live="polite" dbind_loading="hide">
      Showing <span dbind_page-info="from"></span>-<span dbind_page-info="to"></span>
      of <span dbind_page-info="total"></span> products
    </p>
 
    <!-- Loading skeleton (hidden from SR) -->
    <div class="skeleton-grid" dbind_loading="show" aria-hidden="true">
      <div class="skeleton-card"></div>
      <div class="skeleton-card"></div>
      <div class="skeleton-card"></div>
    </div>
 
    <!-- Product grid -->
    <ul class="product-grid" dbind_loading="hide" role="list">
      <li dbind_repeat="data" role="listitem" class="product-card">
        <a
          dbind_href="url"
          dbind_aria-label="productAccessibleName"
          class="product-link"
        >
          <img
            dbind_src="image"
            dbind_alt="name"
            loading="lazy"
          >
          <div class="product-info">
            <h2 class="product-name" dbind_data="name"></h2>
            <div class="product-rating">
              <!-- Visual stars hidden from SR -->
              <span aria-hidden="true" dbind_data="ratingStars"></span>
              <!-- Accessible rating -->
              <span class="sr-only">
                Rated <span dbind_data="rating"></span> out of 5 stars
              </span>
              <span aria-hidden="true">
                (<span dbind_data="reviewCount"></span>)
              </span>
            </div>
            <p class="product-price" dbind_data="price" dbind_format="currency:USD"></p>
 
            <!-- Stock status -->
            <span class="stock-status" dbind_class="stockClass">
              <span dbind_if="stock>10">In Stock</span>
              <span dbind_if="stock<=10">Only <span dbind_data="stock"></span> left</span>
              <span dbind_if="stock==0">Out of Stock</span>
            </span>
          </div>
        </a>
 
        <!-- Action buttons -->
        <div class="product-actions">
          <button
            dbind_aria-label="addToCartLabel"
            dbind_click="addToCart:{{id}}"
            dbind_unless="stock==0"
            class="btn-cart"
          >
            <span aria-hidden="true">🛒</span>
            <span class="btn-text">Add to Cart</span>
          </button>
          <button
            dbind_aria-label="wishlistLabel"
            dbind_click="toggleWishlist:{{id}}"
            dbind_aria-pressed="isWishlisted"
            class="btn-wishlist"
          >
            <span aria-hidden="true" dbind_hide="isWishlisted"></span>
            <span aria-hidden="true" dbind_show="isWishlisted"></span>
            <span class="sr-only" dbind_data="wishlistSRText"></span>
          </button>
        </div>
      </li>
    </ul>
 
    <!-- Empty state -->
    <div class="empty-state" dbind_empty="data" dbind_live="polite">
      <h2>No products found</h2>
      <p>Try adjusting your search terms.</p>
    </div>
 
    <!-- Pagination -->
    <nav aria-label="Product pages" class="pagination" dbind_loading="hide">
      <button
        dbind_aria-label="prevPageLabel"
        dbind_hide="isFirstPage"
        dbind_click="prevPage"
      >
        ← Previous
      </button>
      <span aria-current="page">
        Page <span dbind_page-info="page"></span> of <span dbind_page-info="totalPages"></span>
      </span>
      <button
        dbind_aria-label="nextPageLabel"
        dbind_hide="isLastPage"
        dbind_click="nextPage"
      >
        Next →
      </button>
    </nav>
  </div>
 
  <!-- Cart notification -->
  <div
    class="toast"
    role="status"
    dbind_live="polite"
    dbind_show="showCartToast"
  >
    <span dbind_data="cartToastMessage"></span>
  </div>
</main>

CSS for screen reader only content:

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

Best Practices

1. Always Test with Screen Readers

Test your dynamic content with actual screen readers (NVDA, VoiceOver, JAWS).

2. Use Semantic HTML First

ARIA should enhance, not replace, semantic HTML:

<!-- Good: Semantic HTML with ARIA enhancement -->
<button dbind_aria-expanded="isOpen">Toggle Menu</button>
 
<!-- Avoid: ARIA on non-semantic elements -->
<div role="button" tabindex="0">Toggle Menu</div>

3. Don't Overuse Live Regions

Only announce truly important changes:

<!-- Good: Announce important updates -->
<div dbind_live="assertive" dbind_error></div>
 
<!-- Avoid: Announcing every change -->
<div dbind_live="assertive" dbind_data="mousePosition"></div>

4. Provide Context in Labels

Make labels descriptive enough to stand alone:

<!-- Good: Specific label -->
<button dbind_aria-label="'Delete ' + itemName">Delete</button>
 
<!-- Avoid: Generic label -->
<button aria-label="Delete">Delete</button>

Next Steps