# Accessible Component Patterns This document provides code examples for creating accessible components in ThrillWiki. Follow these patterns to ensure WCAG 2.1 AA compliance. ## Button ### Standard Button ```django {% include 'components/ui/button.html' with text='Save Changes' variant='primary' type='submit' %} ``` ### Icon Button (REQUIRED: aria_label) ```django {% include 'components/ui/button.html' with icon=close_svg size='icon' aria_label='Close dialog' variant='ghost' %} ``` **Important**: Icon-only buttons MUST include `aria_label` for screen reader accessibility. ### Disabled Button ```django {% include 'components/ui/button.html' with text='Submit' disabled=True %} ``` ### Button with HTMX ```django {% include 'components/ui/button.html' with text='Load More' hx_get='/api/items?page=2' hx_target='#item-list' hx_swap='beforeend' %} ``` ## Form Field ### Standard Field ```django {% include 'forms/partials/form_field.html' with field=form.email %} ``` The form_field.html component automatically handles: - Label association via `for` attribute - Error message display with proper ARIA - Required field indication - Help text with `aria-describedby` ### Field with Help Text ```django {% include 'forms/partials/form_field.html' with field=form.password help_text='Must be at least 8 characters' %} ``` ### Field with HTMX Validation ```django {% include 'forms/partials/form_field.html' with field=form.username hx_validate=True hx_validate_url='/api/validate-username/' %} ``` ### Complete Form Example ```django
{% csrf_token %}
Account Information {% include 'forms/partials/form_field.html' with field=form.username %} {% include 'forms/partials/form_field.html' with field=form.email %}
Security {% include 'forms/partials/form_field.html' with field=form.password1 %} {% include 'forms/partials/form_field.html' with field=form.password2 %}
{% include 'components/ui/button.html' with text='Create Account' type='submit' variant='primary' %}
``` ## Modal ### Basic Modal ```django {% extends 'components/modals/modal_base.html' %} {% block modal_body %}

Are you sure you want to delete this item?

{% endblock %} ``` ### Modal with Actions ```django {% extends 'components/modals/modal_base.html' %} {% block modal_body %}

This action cannot be undone.

{% endblock %} {% block modal_footer %} {% include 'components/ui/button.html' with text='Delete' variant='destructive' x_on_click='confirmDelete()' %} {% endblock %} ``` The modal_inner.html component automatically provides: - `role="dialog"` and `aria-modal="true"` - `aria-labelledby` pointing to title - `aria-describedby` pointing to body (and subtitle if present) - Focus trap with Tab/Shift+Tab cycling - Home/End key support for first/last focusable element - Escape key to close (configurable) - Auto-focus on first focusable element ## Navigation Menu ### Dropdown Menu ```django
``` ## Search ### Accessible Search with Results ```django
``` ### Search Result Item ```django
{{ result.name }} {{ result.type }}
``` ## Live Regions ### Status Announcements ```django
{{ status_message }}
``` Use `aria-live="polite"` for non-urgent updates that can wait for user to finish current action. ### Alert Messages ```django
{{ error_message }}
``` Use `aria-live="assertive"` for critical errors that require immediate attention. ### Loading State ```django
Loading results...
``` ## Images ### Meaningful Image ```django {{ park.name }} - {{ park.location }} ``` ### Decorative Image ```django ``` ### Avatar with Name ```django {% if user.profile.avatar %} {{ user.get_full_name|default:user.username }}'s profile picture {% else %} {% endif %} ``` ## Breadcrumbs ```django {% include 'components/navigation/breadcrumbs.html' %} ``` The breadcrumbs component automatically provides: - `