# 1.4 Visual Presentation
Color, contrast, and visual hierarchy must meet accessibility standards.
## Success Criteria
### 1.4.1 Color Independence (Level A)
**Requirement**: Positive and negative values, gains and losses, and status indicators must not rely on color alone. Text labels, icons, or patterns must accompany color coding.
**Intent**: Red/green for profit/loss is invisible to colorblind users (8% of men). Multiple indicators ensure everyone perceives meaning.
**Benefits**:
- **Colorblind users**: Can distinguish positive/negative values
- **Low vision users**: Not dependent on color perception
- **All users**: Clearer at a glance
**Techniques**:
```tsx
// ❌ Inaccessible - color only
<span className={profit > 0 ? 'text-green' : 'text-red'}>
{profit}%
</span>
// ✅ Accessible - color + symbol + aria-label
<PriceChange value={profit}>
<span aria-label={profit > 0 ? `Up ${profit} percent` : `Down ${Math.abs(profit)} percent`}>
{profit > 0 ? '▲' : '▼'} {profit > 0 ? '+' : ''}{profit}%
</span>
</PriceChange>
// Status indicators
<TransactionStatus status={status}>
{status === 'pending' && <ClockIcon aria-hidden="true" />}
{status === 'confirmed' && <CheckIcon aria-hidden="true" />}
{status === 'failed' && <XIcon aria-hidden="true" />}
<span>{status}</span>
</TransactionStatus>
```
**Failures**:
- Green/red as only profit/loss indicator
- Status shown only by colored dot
- Charts with color-only legends
---
### 1.4.2 Non-Visual Chart Access (Level AA)
**Requirement**: Price charts and graphs must have non-visual data access through data tables, summaries, or screen reader announcements.
**Intent**: Charts are inherently visual. Alternative access ensures the data is available to all.
**Benefits**:
- **Blind users**: Access to price/trend information
- **Cognitive disabilities**: Summaries may be clearer than charts
**Techniques**:
```tsx
<PriceChart data={priceData}>
{/* Visual chart */}
<CandlestickChart aria-hidden="true" />
{/* Screen reader summary */}
<div className="sr-only" aria-live="polite">
<p>
{token} price over the last 24 hours:
Started at ${priceData.open},
High of ${priceData.high},
Low of ${priceData.low},
Currently ${priceData.close}.
{priceData.change > 0 ? 'Up' : 'Down'} {Math.abs(priceData.change)}%.
</p>
</div>
{/* Expandable data table */}
<details>
<summary>View price data as table</summary>
<table>
<thead>
<tr>
<th>Time</th>
<th>Price</th>
<th>Volume</th>
</tr>
</thead>
<tbody>
{priceData.points.map(point => (
<tr key={point.time}>
<td>{formatTime(point.time)}</td>
<td>${point.price}</td>
<td>{point.volume}</td>
</tr>
))}
</tbody>
</table>
</details>
</PriceChart>
```
**Failures**:
- Charts with no alternative data access
- `aria-hidden` on charts without alternative
- Data tables that aren't keyboard accessible
---
### 1.4.3 Contrast Ratios (Level AA)
**Requirement**: All text and interactive elements meet WCAG 2.2 AA contrast requirements: 4.5:1 for normal text, 3:1 for large text and UI components.
**Intent**: Sufficient contrast ensures readability for low vision users and in various lighting conditions.
**Benefits**:
- **Low vision users**: Can read interface text
- **All users**: Better readability in sunlight
**Techniques**:
```css
/* Ensure sufficient contrast */
:root {
--text-primary: #1a1a1a; /* Against white: 16.1:1 */
--text-secondary: #595959; /* Against white: 7:1 */
--text-on-primary: #ffffff; /* Against blue-600: 8.6:1 */
--border-interactive: #767676; /* 4.5:1 minimum */
}
/* Focus indicators */
button:focus-visible {
outline: 2px solid #0066cc;
outline-offset: 2px;
}
```
**Testing**:
- Use browser dev tools contrast checker
- Test with [WebAIM Contrast Checker](https://webaim.org/resources/contrastchecker/)
- Verify in light and dark modes
**Failures**:
- Low contrast placeholder text
- Light gray text on white backgrounds
- Focus indicators that don't meet 3:1
---
### 1.4.4 Display Mode Support (Level AAA)
**Requirement**: UI supports high contrast mode, dark mode, and light mode with user preference detection and manual override.
**Intent**: Users have different visual needs and preferences. System-wide preferences should be respected.
**Benefits**:
- **Low vision users**: High contrast improves visibility
- **Light sensitivity**: Dark mode reduces strain
- **User preference**: Respects system settings
**Techniques**:
```tsx
// Respect system preferences
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
const prefersHighContrast = window.matchMedia('(prefers-contrast: more)').matches;
// CSS
@media (prefers-color-scheme: dark) {
:root {
--bg-primary: #0a0a0a;
--text-primary: #ffffff;
}
}
@media (prefers-contrast: more) {
:root {
--text-primary: #000000;
--bg-primary: #ffffff;
--border-color: #000000;
}
}
// Manual toggle
<ThemeToggle
options={['light', 'dark', 'high-contrast']}
aria-label="Select display mode"
/>
```
**Failures**:
- No dark mode support
- Ignoring system preferences
- High contrast mode breaks layout
---
## Testing Checklist
- [ ] Profit/loss has non-color indicators
- [ ] Charts have data tables or summaries
- [ ] All text meets 4.5:1 contrast
- [ ] Interactive elements meet 3:1 contrast
- [ ] Focus indicators are visible
- [ ] Dark mode functions correctly
- [ ] System preferences are respected
## Related Components
- [PriceChange.tsx](../../components/PriceChange.tsx)
- [PriceChart.tsx](../../components/PriceChart.tsx)
- [ThemeProvider.tsx](../../components/ThemeProvider.tsx)