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:
| Attribute | Purpose | Example |
|---|---|---|
aria-label | Accessible name | Button labels, icon descriptions |
aria-describedby | ID of describing element | Form field descriptions |
aria-labelledby | ID of labeling element | Modal titles |
aria-hidden | Hide from assistive tech | Decorative elements |
aria-expanded | Expandable state | Accordions, dropdowns |
aria-selected | Selection state | Tabs, list items |
aria-pressed | Toggle button state | Toggle buttons |
aria-checked | Checkbox/radio state | Custom checkboxes |
aria-disabled | Disabled state | Disabled buttons |
aria-busy | Loading state | Loading regions |
aria-current | Current item | Navigation, pagination |
aria-valuenow | Current value | Progress bars, sliders |
aria-valuemin | Minimum value | Progress bars, sliders |
aria-valuemax | Maximum value | Progress 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
| Level | Behavior | Use For |
|---|---|---|
polite | Announced when user is idle | Status updates, new content |
assertive | Announced immediately | Errors, critical alerts |
off | Not announced | Disable 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
- Animations - Accessible transitions
- Loading - Accessible loading states
- Forms - Accessible form handling