Instructions do not rely solely on sensory characteristics like shape, color, size, visual location, orientation, or sound
1. Perceivable
1.3 Adaptable
WCAG 2.0
Instructions and content must not rely solely on sensory characteristics to convey meaning. Users with different disabilities may not be able to perceive color, shape, size, position, orientation, or sound. Always provide multiple ways to identify and understand content.
Color only
"Click the red button" - unusable for color blind users
Shape only
"Select the circular icon" - not clear for blind users
Position only
"Use the menu on the right" - varies by screen size
Sound only
"Listen for the beep" - unusable for deaf users
Size only
"Click the small button" - relative and unclear
Orientation only
"Rotate your device" - may not be possible
"To save your work, click the green button. To cancel, click the red button."
"To save your work, click the 'Save' button. To cancel, click the 'Cancel' button."
✅ Even in color blind view: Clear labels and icons make the buttons identifiable!
<!-- Bad: Color only -->
<button class="red-button">Delete</button>
<button class="green-button">Save</button>
<!-- Good: Color + text + icons -->
<button class="delete-button">
<svg aria-hidden="true"><!-- delete icon --></svg>
Delete
</button>
<button class="save-button">
<svg aria-hidden="true"><!-- save icon --></svg>
Save
</button>
<!-- Bad: Position only -->
<p>Click the button on the right to continue.</p>
<!-- Good: Clear identification -->
<p>Click the "Continue" button to proceed.</p>
<button id="continue-btn">Continue</button>
<!-- Bad: Shape only -->
<p>Select the circular option.</p>
<input type="radio" id="option1">
<!-- Good: Shape + label -->
<label for="option1">
<input type="radio" id="option1">
Premium Plan (recommended)
</label>
/* CSS for accessible styling */
.error {
color: red;
background: url('error-icon.svg') no-repeat;
padding-left: 20px;
}
.error::before {
content: "Error: ";
font-weight: bold;
}
.success {
color: green;
background: url('success-icon.svg') no-repeat;
padding-left: 20px;
}
.success::before {
content: "Success: ";
font-weight: bold;
}// Accessible button component
function AccessibleButton({ type, children, onClick, ...props }) {
const getButtonConfig = (type) => {
const configs = {
save: {
className: 'bg-green-600 hover:bg-green-700',
icon: <SaveIcon />,
ariaLabel: 'Save your changes'
},
delete: {
className: 'bg-red-600 hover:bg-red-700',
icon: <DeleteIcon />,
ariaLabel: 'Delete this item'
},
cancel: {
className: 'bg-gray-600 hover:bg-gray-700',
icon: <CancelIcon />,
ariaLabel: 'Cancel operation'
}
};
return configs[type] || {};
};
const config = getButtonConfig(type);
return (
<button
className={`flex items-center gap-2 px-4 py-2 text-white rounded font-medium ${config.className}`}
aria-label={config.ariaLabel}
onClick={onClick}
{...props}
>
{config.icon}
{children}
</button>
);
}
// Accessible status messages
function StatusMessage({ type, message }) {
const getStatusConfig = (type) => {
return {
error: {
className: 'bg-red-50 border-red-200 text-red-800',
icon: <ErrorIcon className="text-red-600" />,
prefix: 'Error: '
},
success: {
className: 'bg-green-50 border-green-200 text-green-800',
icon: <SuccessIcon className="text-green-600" />,
prefix: 'Success: '
},
warning: {
className: 'bg-yellow-50 border-yellow-200 text-yellow-800',
icon: <WarningIcon className="text-yellow-600" />,
prefix: 'Warning: '
}
}[type];
};
const config = getStatusConfig(type);
return (
<div
className={`flex items-start gap-3 p-4 border rounded ${config.className}`}
role="alert"
aria-live="polite"
>
{config.icon}
<div>
<span className="font-medium">{config.prefix}</span>
{message}
</div>
</div>
);
}
// Usage examples
<AccessibleButton type="save" onClick={handleSave}>
Save Changes
</AccessibleButton>
<StatusMessage
type="success"
message="Your changes have been saved successfully."
/>