Best Practices
Follow these guidelines to ensure your website meets federal standards for accessibility, performance, and user experience.
Best Practices for Federal Websites
This comprehensive guide covers essential best practices for building and maintaining federally compliant websites using this template. Following these practices ensures your website serves all users effectively while meeting federal requirements and standards.
Quick Compliance Checklist
- Section 508: Meet WCAG 2.1 AA accessibility standards
- 21st Century IDEA: Modern, mobile-responsive design
- Privacy Act: Protect user information and data
- Plain Language: Clear, simple communication
- Digital Analytics: DAP implementation for federal sites
Table of Contents
- Accessibility Compliance
- Federal Legal Requirements
- Performance & User Experience
- Content Strategy & Plain Language
- Security & Privacy
- Mobile Responsiveness
- SEO & Discoverability
- Testing & Quality Assurance
- Maintenance & Updates
Accessibility Compliance
WCAG 2.1 AA Compliance
All federal websites must meet Web Content Accessibility Guidelines (WCAG) 2.1 Level AA standards under Section 508 of the Rehabilitation Act. This ensures your website is accessible to people with disabilities, including those who use screen readers, keyboard navigation, or other assistive technologies.
The Four Principles of Accessibility (POUR):
Perceivable
- Text Alternatives: Provide alt text for all images
- Captions: Include captions for videos
- Color Contrast: Maintain 4.5:1 ratio for normal text, 3:1 for large text
- Resize Text: Support 200% zoom without horizontal scrolling
<!-- Good: Descriptive alt text -->
<img src="chart.png" alt="Bar chart showing 30% increase in applications from 2020 to 2023">
<!-- Bad: Generic alt text -->
<img src="chart.png" alt="Chart">
Operable
- Keyboard Navigation: All functionality available via keyboard
- Skip Links: Provide skip navigation links
- Focus Indicators: Visible focus indicators for all interactive elements
- Time Limits: Provide warnings and extensions for time limits
<!-- Skip navigation -->
<a class="usa-skipnav" href="#main-content">Skip to main content</a>
<!-- Keyboard accessible button -->
<button type="button"
onclick="handleClick()"
onkeypress="handleKeyPress(event)">
Click me
</button>
Understandable
- Language: Declare page language
- Labels: Clear labels for form inputs
- Error Messages: Helpful error identification and suggestions
- Consistent Navigation: Same navigation structure across pages
<!-- Declare language -->
<html lang="en">
<!-- Clear form labels -->
<label for="email">
Email Address
<span class="usa-hint">We'll only use this to respond to your inquiry</span>
</label>
<input type="email" id="email" name="email" required>
Testing Accessibility
Automated Testing
Command Line Testing:
# Using Pa11y (comprehensive testing)
npm install -g pa11y
pa11y https://your-site.gov --standard WCAG2AA
# Test multiple pages
pa11y-ci --sitemap https://your-site.gov/sitemap.xml
# Using Axe CLI
npm install -g @axe-core/cli
axe https://your-site.gov --rules wcag2a,wcag2aa,wcag21aa
# Integration testing with this template
npm run test:a11y # Built-in accessibility testing
Browser Extensions:
- axe DevTools (Chrome, Firefox): Real-time accessibility scanning
- WAVE (Web Accessibility Evaluation Tool): Visual accessibility testing
- Lighthouse (Built into Chrome): Comprehensive audits including accessibility
Manual Testing Checklist
Keyboard Navigation (Required for all interactive elements):
- Navigate using only keyboard (Tab, Enter, Arrow keys, Space)
- Verify logical tab order follows visual layout
- Check all interactive elements are focusable
- Test dropdown menus and modal dialogs
- Ensure skip links work properly
- Test form navigation and submission
Screen Reader Testing (Test with at least one):
- NVDA (free, Windows): Download from nvaccess.org
- JAWS (Windows): Most used by federal employees
- VoiceOver (macOS, iOS): Built-in to Apple devices
- TalkBack (Android): Built-in Android screen reader
Visual & Content Testing:
- Check color contrast with browser tools (4.5:1 normal text, 3:1 large text)
- Zoom to 200% and verify no horizontal scroll
- Test with Windows High Contrast mode
- Disable CSS and verify content structure makes sense
- Test with browser’s reader mode
- Verify all images have meaningful alt text
Testing Script Example:
#!/bin/bash
# accessibility-test.sh - Comprehensive accessibility testing
echo "Starting accessibility tests..."
# Start local server if needed
npm run start &
SERVER_PID=$!
sleep 5
# Run automated tests
echo "Running Pa11y tests..."
pa11y http://localhost:8080 --standard WCAG2AA --reporter cli
echo "Running Lighthouse accessibility audit..."
lighthouse http://localhost:8080 --only-categories=accessibility --output=html --output-path=./reports/accessibility-report.html
# Stop server
kill $SERVER_PID
echo "Tests complete. Check ./reports/ for detailed results."
Federal Legal Requirements
Section 508 Rehabilitation Act
Key Requirements:
- Electronic content must be accessible to people with disabilities
- Applies to all federal agencies and contractors
- Based on WCAG 2.0 Level AA (updated to WCAG 2.1)
Implementation Checklist:
- Semantic HTML structure
- Proper heading hierarchy (h1-h6)
- Alternative text for images
- Keyboard navigation support
- Screen reader compatibility
- Color contrast compliance
- Form labels and error messages
21st Century Integrated Digital Experience Act (IDEA)
Requirements:
- Websites must be mobile-friendly
- Must have a consistent appearance
- Must be accessible
- Must use a secure connection (HTTPS)
- Must have a search function
- Must provide contact information
Template Compliance:
<!-- This template includes all IDEA requirements: -->
<!-- Mobile-friendly responsive design -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Consistent USWDS appearance -->
<link rel="stylesheet" href="/assets/css/main.css">
<!-- Search functionality -->
<form class="usa-search usa-search--small">
<div role="search">
<label class="usa-sr-only" for="search-field-small">Search</label>
<input class="usa-input" id="search-field-small" type="search" name="search">
<button class="usa-button" type="submit">
<span class="usa-sr-only">Search</span>
</button>
</div>
</form>
<!-- Contact information in footer -->
<div class="usa-footer__contact-info">
<a href="/contact/">Contact Us</a>
</div>
Plain Writing Act of 2010
Requirements:
- Use plain language in government documents
- Write for your audience
- Organize information logically
- Use active voice
- Use short sentences
Writing Guidelines:
<!-- Bad -->
# Utilization of Electronic Communication Systems
Pursuant to agency regulations, the utilization of electronic
communication systems for the transmission of information...
<!-- Good -->
# How to Use Email
You can use email to send information to other employees.
Privacy Act of 1974
Key Requirements:
- Protect personal information
- Provide privacy notices
- Limit data collection to necessary information
- Provide users control over their data
Implementation:
<!-- Privacy notice example -->
<div class="usa-alert usa-alert--info">
<div class="usa-alert__body">
<h4 class="usa-alert__heading">Privacy Notice</h4>
<p class="usa-alert__text">
This form collects personal information under the authority of [Legal Authority].
The information will be used to [Purpose]. Providing this information is
[voluntary/required]. See our <a href="/privacy/">Privacy Policy</a> for details.
</p>
</div>
</div>
Paperwork Reduction Act
Requirements:
- OMB approval for information collection from the public
- Display OMB control numbers
- Estimate burden time
Form Requirements:
<!-- OMB approval notice -->
<div class="usa-form-note">
<p><strong>OMB Control Number:</strong> 1234-5678</p>
<p><strong>Expiration Date:</strong> 12/31/2025</p>
<p><strong>Estimated Burden:</strong> 15 minutes</p>
<p>
<small>
The Paperwork Reduction Act requires us to tell you why we are collecting
this information, how we will use it, and whether you have to give it to us.
</small>
</p>
</div>
Performance & User Experience
Core Web Vitals
Target these metrics for optimal user experience:
- LCP (Largest Contentful Paint): < 2.5 seconds
- FID (First Input Delay): < 100 milliseconds
- CLS (Cumulative Layout Shift): < 0.1
Optimization Techniques
Images
<!-- Use responsive images -->
<picture>
<source
media="(min-width: 1024px)"
srcset="hero-large.webp 1920w, hero-large-2x.webp 3840w"
sizes="100vw">
<source
media="(min-width: 640px)"
srcset="hero-medium.webp 1024w, hero-medium-2x.webp 2048w"
sizes="100vw">
<img
src="hero-small.jpg"
srcset="hero-small.webp 640w, hero-small-2x.webp 1280w"
sizes="100vw"
alt="Hero image description"
loading="lazy"
decoding="async">
</picture>
Critical CSS
<!-- Inline critical CSS -->
<style>
/* Critical above-the-fold styles */
.hero { /* ... */ }
</style>
<!-- Load non-critical CSS asynchronously -->
<link rel="preload" href="/css/main.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
JavaScript Loading
<!-- Defer non-critical scripts -->
<script src="/js/analytics.js" defer></script>
<!-- Async for independent scripts -->
<script src="/js/chat-widget.js" async></script>
<!-- Module scripts are deferred by default -->
<script type="module" src="/js/app.js"></script>
Additional Performance Monitoring
Real User Monitoring (RUM):
// Monitor Core Web Vitals
function observeWebVitals() {
// Largest Contentful Paint
new PerformanceObserver((list) => {
const entries = list.getEntries();
const lastEntry = entries[entries.length - 1];
console.log('LCP:', lastEntry.startTime);
}).observe({entryTypes: ['largest-contentful-paint']});
// First Input Delay
new PerformanceObserver((list) => {
const entries = list.getEntries();
entries.forEach((entry) => {
console.log('FID:', entry.processingStart - entry.startTime);
});
}).observe({entryTypes: ['first-input']});
// Cumulative Layout Shift
new PerformanceObserver((list) => {
const entries = list.getEntries();
entries.forEach((entry) => {
if (!entry.hadRecentInput) {
console.log('CLS:', entry.value);
}
});
}).observe({entryTypes: ['layout-shift']});
}
// Initialize monitoring
if ('PerformanceObserver' in window) {
observeWebVitals();
}
Performance Budget Example:
{
"performanceBudget": {
"firstContentfulPaint": "2s",
"firstMeaningfulPaint": "2s",
"largestContentfulPaint": "2.5s",
"interactive": "3.8s",
"firstInputDelay": "100ms",
"cumulativeLayoutShift": "0.1",
"totalBlockingTime": "300ms",
"bundle": "170kb",
"requests": "20"
}
}
Content Strategy & Plain Language
Plain Language
Follow federal plain language guidelines:
Before
“Pursuant to the requirements set forth in Section 508 of the Rehabilitation Act, electronic and information technology developed, procured, maintained, or used by federal agencies must be accessible.”
After
“Federal agencies must make their electronic content accessible to people with disabilities, as required by Section 508.”
Content Structure
# Clear, Descriptive Heading
Lead paragraph that summarizes the key points.
## Organized Sections
- Use bullet points for lists
- Keep paragraphs short (2-3 sentences)
- One idea per paragraph
### Subsections for Details
Break complex information into digestible chunks.
Writing for the Web
- Front-load content: Put most important information first
- Use headings: Break up content with descriptive headings
- Active voice: “We will process your application” not “Your application will be processed”
- Short sentences: Aim for 20 words or less
- Common words: Use “help” instead of “facilitate”
Content Auditing Process
Quarterly Content Review Checklist:
- Review all page content for accuracy
- Check for outdated information
- Verify all links work correctly
- Update contact information
- Review forms and processes
- Check compliance with current regulations
- Validate accessibility of new content
Content Governance:
# Content Approval Process
1. **Draft**: Content creator writes initial draft
2. **SME Review**: Subject matter expert reviews for accuracy
3. **Editorial Review**: Editor checks for plain language compliance
4. **Legal Review**: Legal team reviews for compliance (if needed)
5. **Accessibility Review**: Check for accessibility issues
6. **Final Approval**: Department head approves for publication
7. **Publishing**: Web team publishes content
8. **Review Schedule**: Set next review date
Translation and Multilingual Support
Executive Order 13166 Requirements:
- Provide meaningful access for Limited English Proficiency (LEP) individuals
- Identify frequently encountered languages in your service area
- Translate vital documents
Implementation Example:
<!-- Language selector -->
<div class="usa-language-selector">
<ul class="usa-language-selector__list">
<li class="usa-language-selector__list-item">
<a href="/" class="usa-language-selector__link" hreflang="en" lang="en">
English
</a>
</li>
<li class="usa-language-selector__list-item">
<a href="/es/" class="usa-language-selector__link" hreflang="es" lang="es">
Español
</a>
</li>
</ul>
</div>
<!-- Page language declaration -->
<html lang="en">
<!-- Alternative language versions -->
<link rel="alternate" hreflang="es" href="https://agency.gov/es/page/">
<link rel="alternate" hreflang="x-default" href="https://agency.gov/page/">
Security & Privacy
Content Security Policy
<!-- Implement CSP headers -->
<meta http-equiv="Content-Security-Policy"
content="default-src 'self';
script-src 'self' 'unsafe-inline' https://dap.digitalgov.gov;
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
font-src 'self' data:;">
HTTPS Requirements
- Always use HTTPS in production
- Implement HSTS headers
- Update all resource URLs to HTTPS
// Redirect HTTP to HTTPS
if (location.protocol !== 'https:' && location.hostname !== 'localhost') {
location.protocol = 'https:';
}
Data Protection
// Sanitize user input
function sanitizeInput(input) {
const div = document.createElement('div');
div.textContent = input;
return div.innerHTML;
}
// Validate email addresses
function validateEmail(email) {
const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return re.test(email);
}
Advanced Security Headers
Security Headers Implementation:
<meta http-equiv="Content-Security-Policy"
content="default-src 'self';
script-src 'self' 'unsafe-inline' https://dap.digitalgov.gov https://www.googletagmanager.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data: https: *.gov;
font-src 'self' data:;
connect-src 'self' https://analytics.usa.gov;
frame-ancestors 'none';
base-uri 'self';
object-src 'none';">
<meta http-equiv="X-Content-Type-Options" content="nosniff">
<meta http-equiv="X-Frame-Options" content="DENY">
<meta http-equiv="X-XSS-Protection" content="1; mode=block">
<meta http-equiv="Referrer-Policy" content="strict-origin-when-cross-origin">
<meta http-equiv="Permissions-Policy" content="geolocation=(), microphone=(), camera=()">
Server Security Configuration (.htaccess example):
# Force HTTPS
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
# Security Headers
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "DENY"
Header always set X-XSS-Protection "1; mode=block"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
# Remove server signature
ServerTokens Prod
ServerSignature Off
Privacy Implementation
Cookie Consent (if cookies are used):
<div id="cookie-notice" class="usa-alert usa-alert--info" role="alert">
<div class="usa-alert__body">
<h4 class="usa-alert__heading">Cookie Notice</h4>
<p class="usa-alert__text">
This website uses cookies to enhance user experience and analyze website traffic.
By continuing to use this site, you consent to our use of cookies.
<a href="/privacy/">Learn more about our privacy practices</a>.
</p>
<button class="usa-button usa-button--outline" onclick="acceptCookies()">
Accept
</button>
</div>
</div>
<script>
function acceptCookies() {
localStorage.setItem('cookieConsent', 'true');
document.getElementById('cookie-notice').style.display = 'none';
}
// Check if consent already given
if (localStorage.getItem('cookieConsent')) {
document.getElementById('cookie-notice').style.display = 'none';
}
</script>
Data Minimization Example:
<!-- Only collect necessary information -->
<form class="usa-form">
<fieldset class="usa-fieldset">
<legend class="usa-legend">Contact Information (Required fields only)</legend>
<label class="usa-label" for="name">
Full Name <abbr title="required" class="usa-hint--required">*</abbr>
</label>
<input class="usa-input" id="name" name="name" type="text" required>
<label class="usa-label" for="email">
Email Address <abbr title="required" class="usa-hint--required">*</abbr>
</label>
<span class="usa-hint">We'll only use this to respond to your inquiry</span>
<input class="usa-input" id="email" name="email" type="email" required>
<!-- Don't ask for unnecessary personal information -->
<!-- Remove: SSN, birth date, phone (unless truly needed) -->
</fieldset>
</form>
SEO & Discoverability
Essential Meta Tags
<head>
<!-- Basic metadata -->
<title>Page Title - Agency Name</title>
<meta name="description" content="Clear description under 160 characters">
<!-- Open Graph for social sharing -->
<meta property="og:title" content="Page Title">
<meta property="og:description" content="Page description">
<meta property="og:image" content="https://agency.gov/image.jpg">
<meta property="og:url" content="https://agency.gov/page">
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@agencyhandle">
<!-- Canonical URL -->
<link rel="canonical" href="https://agency.gov/page">
</head>
Structured Data
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "GovernmentService",
"name": "Service Name",
"description": "Service description",
"provider": {
"@type": "GovernmentOrganization",
"name": "Agency Name"
},
"areaServed": {
"@type": "Country",
"name": "United States"
},
"audience": {
"@type": "Audience",
"audienceType": "Citizens"
}
}
</script>
Advanced SEO Implementation
Schema.org Structured Data for Government:
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "GovernmentOrganization",
"name": "Your Agency Name",
"alternateName": "AGENCY",
"url": "https://agency.gov",
"logo": "https://agency.gov/assets/img/logo.png",
"contactPoint": {
"@type": "ContactPoint",
"telephone": "1-800-AGENCY",
"contactType": "customer service",
"availableLanguage": ["English", "Spanish"]
},
"address": {
"@type": "PostalAddress",
"streetAddress": "123 Government Way",
"addressLocality": "Washington",
"addressRegion": "DC",
"postalCode": "20500",
"addressCountry": "US"
},
"parentOrganization": {
"@type": "GovernmentOrganization",
"name": "United States Government"
}
}
</script>
Government Service Schema:
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "GovernmentService",
"name": "Service Name",
"description": "Service description",
"provider": {
"@type": "GovernmentOrganization",
"name": "Your Agency Name"
},
"areaServed": {
"@type": "Country",
"name": "United States"
},
"audience": {
"@type": "Audience",
"audienceType": "Citizens"
},
"availableChannel": {
"@type": "ServiceChannel",
"serviceType": "Online",
"serviceUrl": "https://agency.gov/service"
}
}
</script>
XML Sitemap Enhancement:
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:news="http://www.google.com/schemas/sitemap-news/0.9">
<url>
<loc>https://agency.gov/page-url/</loc>
<lastmod>2023-12-01</lastmod>
<changefreq>monthly</changefreq>
<priority>0.5</priority>
</url>
</urlset>
Mobile Responsiveness
Mobile-First Design
// Start with mobile styles
.component {
padding: 1rem;
font-size: 1rem;
}
// Add tablet styles
@media (min-width: 640px) {
.component {
padding: 1.5rem;
font-size: 1.125rem;
}
}
// Add desktop styles
@media (min-width: 1024px) {
.component {
padding: 2rem;
font-size: 1.25rem;
}
}
Touch Targets
Ensure touch targets are at least 44×44 pixels:
.usa-button {
min-height: 44px;
min-width: 44px;
padding: 12px 16px;
}
.link-list a {
display: inline-block;
padding: 8px 0;
margin: 4px 0;
}
Progressive Web App (PWA) Features
Web App Manifest:
{
"name": "Your Agency Name",
"short_name": "AGENCY",
"description": "Agency description",
"start_url": "/",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#005ea2",
"orientation": "portrait-primary",
"icons": [
{
"src": "/assets/img/icon-192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any maskable"
},
{
"src": "/assets/img/icon-512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any maskable"
}
]
}
Service Worker for Offline Support:
// sw.js - Basic service worker for government sites
const CACHE_NAME = 'gov-site-v1';
const urlsToCache = [
'/',
'/assets/css/main.css',
'/assets/js/main.js',
'/offline.html'
];
// Install event
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME)
.then((cache) => cache.addAll(urlsToCache))
);
});
// Fetch event
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request)
.then((response) => {
// Return cached version or fetch from network
return response || fetch(event.request);
})
.catch(() => {
// Show offline page for navigation requests
if (event.request.destination === 'document') {
return caches.match('/offline.html');
}
})
);
});
Mobile Testing Checklist
Device Testing:
- iPhone (Safari)
- Android (Chrome)
- iPad (Safari)
- Android tablet (Chrome)
- Test landscape and portrait orientations
- Test with different screen sizes
Accessibility on Mobile:
- Test with VoiceOver (iOS)
- Test with TalkBack (Android)
- Verify touch targets are at least 44px
- Check swipe gestures work properly
- Test with device zoom enabled
Forms Best Practices
Accessible Forms
<form class="usa-form">
<fieldset class="usa-fieldset">
<legend class="usa-legend">Contact Information</legend>
<!-- Required field -->
<label class="usa-label" for="name">
Full Name <abbr title="required" class="usa-hint--required">*</abbr>
</label>
<span class="usa-hint" id="name-hint">Enter your first and last name</span>
<input
class="usa-input"
id="name"
name="name"
type="text"
aria-describedby="name-hint"
required>
<!-- Error message -->
<div class="usa-form-group usa-form-group--error">
<label class="usa-label usa-label--error" for="email">
Email Address
</label>
<span class="usa-error-message" role="alert">
Please enter a valid email address
</span>
<input
class="usa-input usa-input--error"
id="email"
name="email"
type="email"
aria-invalid="true"
aria-describedby="email-error">
</div>
</fieldset>
<button type="submit" class="usa-button">Submit</button>
</form>
Progressive Enhancement
// Check if JavaScript is available
document.documentElement.className =
document.documentElement.className.replace('no-js', 'js');
// Enhance form if JS is enabled
if (document.documentElement.classList.contains('js')) {
// Add client-side validation
// Add dynamic form fields
// Enable autosave
}
Advanced Form Validation
Client-Side Validation with Accessibility:
class AccessibleFormValidator {
constructor(form) {
this.form = form;
this.errorSummary = null;
this.init();
}
init() {
this.form.addEventListener('submit', this.handleSubmit.bind(this));
this.createErrorSummary();
}
createErrorSummary() {
this.errorSummary = document.createElement('div');
this.errorSummary.className = 'usa-alert usa-alert--error';
this.errorSummary.setAttribute('role', 'alert');
this.errorSummary.setAttribute('aria-live', 'polite');
this.errorSummary.style.display = 'none';
this.form.insertBefore(this.errorSummary, this.form.firstChild);
}
handleSubmit(event) {
const errors = this.validateForm();
if (errors.length > 0) {
event.preventDefault();
this.displayErrors(errors);
this.focusFirstError();
}
}
validateForm() {
const errors = [];
const inputs = this.form.querySelectorAll('input, select, textarea');
inputs.forEach(input => {
const error = this.validateField(input);
if (error) {
errors.push(error);
}
});
return errors;
}
validateField(field) {
// Remove existing error styling
field.classList.remove('usa-input--error');
field.setAttribute('aria-invalid', 'false');
let error = null;
if (field.hasAttribute('required') && !field.value.trim()) {
error = {
field: field,
message: `${this.getFieldLabel(field)} is required.`
};
} else if (field.type === 'email' && field.value && !this.isValidEmail(field.value)) {
error = {
field: field,
message: `Please enter a valid email address.`
};
}
if (error) {
field.classList.add('usa-input--error');
field.setAttribute('aria-invalid', 'true');
}
return error;
}
displayErrors(errors) {
const errorList = errors.map(error =>
`<li><a href="#${error.field.id}">${error.message}</a></li>`
).join('');
this.errorSummary.innerHTML = `
<div class="usa-alert__body">
<h4 class="usa-alert__heading">Please correct the following errors:</h4>
<ul class="usa-list">${errorList}</ul>
</div>
`;
this.errorSummary.style.display = 'block';
}
focusFirstError() {
const firstError = this.form.querySelector('.usa-input--error');
if (firstError) {
firstError.focus();
}
}
getFieldLabel(field) {
const label = this.form.querySelector(`label[for="${field.id}"]`);
return label ? label.textContent.trim().replace('*', '') : field.name;
}
isValidEmail(email) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
}
// Initialize validator on all forms
document.addEventListener('DOMContentLoaded', () => {
document.querySelectorAll('.usa-form').forEach(form => {
new AccessibleFormValidator(form);
});
});
Multi-Step Forms
Step Indicator Implementation:
<div class="usa-step-indicator usa-step-indicator--counters-sm" aria-label="Application progress">
<ol class="usa-step-indicator__segments">
<li class="usa-step-indicator__segment usa-step-indicator__segment--complete">
<span class="usa-step-indicator__segment-label">Personal information</span>
</li>
<li class="usa-step-indicator__segment usa-step-indicator__segment--current" aria-current="step">
<span class="usa-step-indicator__segment-label">Employment history</span>
</li>
<li class="usa-step-indicator__segment">
<span class="usa-step-indicator__segment-label">Review and submit</span>
</li>
</ol>
<div class="usa-step-indicator__header">
<h4 class="usa-step-indicator__heading">
<span class="usa-step-indicator__heading-counter">
<span class="usa-step-indicator__current-step">2</span>
<span class="usa-step-indicator__total-steps">of 3</span>
</span>
<span class="usa-step-indicator__heading-text">Employment history</span>
</h4>
</div>
</div>
Testing & Quality Assurance
Comprehensive Testing Strategy
Testing Pyramid for Government Sites:
#!/bin/bash
# comprehensive-test.sh - Full testing suite
echo "🧪 Starting comprehensive testing suite..."
# 1. Lint and code quality
echo "📋 Running linters..."
npm run lint:js
npm run lint:scss
npm run format -- --check
# 2. Build the site
echo "🏗️ Building site..."
npm run build
# 3. Start test server
echo "🚀 Starting test server..."
npx http-server _site -p 8080 &
SERVER_PID=$!
sleep 3
# 4. Accessibility testing
echo "♿ Testing accessibility..."
pa11y http://localhost:8080 --standard WCAG2AA --reporter cli
pa11y http://localhost:8080/best-practices/ --standard WCAG2AA --reporter cli
pa11y http://localhost:8080/components/ --standard WCAG2AA --reporter cli
# 5. Performance testing
echo "⚡ Testing performance..."
lighthouse http://localhost:8080 \
--output=html \
--output-path=./reports/lighthouse-$(date +%Y%m%d).html \
--chrome-flags="--headless --no-sandbox"
# 6. Security testing
echo "🔒 Testing security headers..."
curl -I http://localhost:8080 | grep -E '(X-|Strict-|Content-Security)'
# 7. Link checking
echo "🔗 Checking links..."
if command -v linkchecker &> /dev/null; then
linkchecker http://localhost:8080
else
echo "Install linkchecker for link validation: pip install linkchecker"
fi
# 8. HTML validation
echo "📝 Validating HTML..."
if command -v tidy &> /dev/null; then
curl -s http://localhost:8080 | tidy -e -q
else
echo "Install tidy for HTML validation: sudo apt-get install tidy"
fi
# Cleanup
kill $SERVER_PID
echo "✅ Testing complete! Check ./reports/ for detailed results."
Cross-Browser Testing:
// browser-test-config.js
module.exports = {
browsers: [
'Chrome >= 90',
'Firefox >= 88',
'Safari >= 14',
'Edge >= 90',
'iOS >= 14',
'Android >= 10'
],
testUrls: [
'/',
'/best-practices/',
'/components/',
'/customization/',
'/contact/'
],
tests: [
'accessibility',
'performance',
'visual-regression',
'functionality'
]
};
Automated Quality Checks
GitHub Actions Workflow:
# .github/workflows/quality-assurance.yml
name: Quality Assurance
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Lint code
run: |
npm run lint:js
npm run lint:scss
- name: Build site
run: npm run build
- name: Test accessibility
run: |
npx http-server _site -p 8080 &
sleep 3
npm run test:a11y
pkill http-server
- name: Lighthouse audit
uses: treosh/lighthouse-ci-action@v9
with:
configPath: '.lighthouserc.json'
uploadArtifacts: true
temporaryPublicStorage: true
Analytics & Privacy
Digital Analytics Program (DAP)
<!-- Include DAP for federal analytics -->
<script async src="https://dap.digitalgov.gov/Universal-Federated-Analytics-Min.js?agency=AGENCY"></script>
Privacy Considerations
- Don’t track personally identifiable information (PII)
- Provide clear privacy policy
- Allow users to opt-out of tracking
- Follow federal privacy requirements
// Check for Do Not Track
if (navigator.doNotTrack === "1") {
// Disable analytics
window['ga-disable-GA_MEASUREMENT_ID'] = true;
}
Privacy-Compliant Analytics
Digital Analytics Program (DAP) Implementation:
<!-- Required for all federal websites -->
<script>
// Check for Do Not Track
if (navigator.doNotTrack !== "1") {
// Load DAP analytics
(function() {
var dapScript = document.createElement('script');
dapScript.async = true;
dapScript.src = 'https://dap.digitalgov.gov/Universal-Federated-Analytics-Min.js?agency=AGENCY';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(dapScript, s);
})();
}
</script>
Custom Analytics (Privacy-First):
// privacy-analytics.js
class PrivacyAnalytics {
constructor(options = {}) {
this.respectDNT = options.respectDNT !== false;
this.sessionOnly = options.sessionOnly !== false;
this.endpoint = options.endpoint || '/analytics';
if (this.shouldTrack()) {
this.init();
}
}
shouldTrack() {
// Respect Do Not Track
if (this.respectDNT && navigator.doNotTrack === "1") {
return false;
}
// Check for consent (if required)
if (this.requiresConsent && !this.hasConsent()) {
return false;
}
return true;
}
init() {
this.trackPageView();
this.trackUserInteractions();
}
trackPageView() {
const data = {
type: 'pageview',
path: window.location.pathname,
referrer: document.referrer,
timestamp: new Date().toISOString(),
// No personal identifiers
userAgent: this.getGeneralUserAgent()
};
this.sendEvent(data);
}
trackUserInteractions() {
// Track important interactions without PII
document.addEventListener('click', (e) => {
if (e.target.matches('a[href^="tel:"], a[href^="mailto:"], .usa-button')) {
this.sendEvent({
type: 'interaction',
element: e.target.tagName,
action: 'click',
path: window.location.pathname
});
}
});
}
getGeneralUserAgent() {
// Return only general browser/OS info
const ua = navigator.userAgent;
if (ua.includes('Chrome')) return 'Chrome';
if (ua.includes('Firefox')) return 'Firefox';
if (ua.includes('Safari')) return 'Safari';
if (ua.includes('Edge')) return 'Edge';
return 'Other';
}
sendEvent(data) {
// Send to privacy-compliant endpoint
fetch(this.endpoint, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(data)
}).catch(() => {
// Fail silently
});
}
}
// Initialize privacy-compliant analytics
new PrivacyAnalytics({
respectDNT: true,
sessionOnly: true
});
Maintenance & Updates
Regular Maintenance Schedule
Monthly Tasks:
- Review and update content
- Check all forms and functionality
- Monitor website performance
- Review analytics for user behavior
- Check for broken links
- Update contact information if needed
Quarterly Tasks:
- Comprehensive accessibility audit
- Security vulnerability scan
- Performance optimization review
- Content strategy review
- User feedback analysis
- Mobile experience testing
Annual Tasks:
- Complete security assessment
- USWDS version update
- Comprehensive user testing
- Privacy policy review
- Disaster recovery testing
- Staff training updates
Dependency Updates:
#!/bin/bash
# update-dependencies.sh
echo "🔄 Checking for updates..."
# Check for outdated packages
npm outdated
# Update USWDS (test thoroughly)
echo "📦 Updating USWDS..."
npm update @uswds/uswds
# Update Eleventy
echo "📦 Updating Eleventy..."
npm update @11ty/eleventy
# Security audit
echo "🔒 Running security audit..."
npm audit
npm audit fix
# Test after updates
echo "🧪 Running tests..."
npm run build
npm run test:a11y
echo "✅ Updates complete. Review changes before deploying."
Backup and Recovery
Backup Strategy:
#!/bin/bash
# backup.sh - Backup website content and configuration
BACKUP_DIR="/backups/$(date +%Y-%m-%d)"
mkdir -p $BACKUP_DIR
# Backup source code
echo "💾 Backing up source code..."
tar -czf $BACKUP_DIR/source-code.tar.gz src/ eleventy.config.js package*.json
# Backup generated site
echo "💾 Backing up generated site..."
tar -czf $BACKUP_DIR/generated-site.tar.gz _site/
# Backup configuration
echo "💾 Backing up configuration..."
cp -r .github/ $BACKUP_DIR/
echo "✅ Backup complete: $BACKUP_DIR"
Testing Checklist
Pre-Launch
- Accessibility audit (automated and manual)
- Cross-browser testing (Chrome, Firefox, Safari, Edge)
- Mobile device testing (iOS, Android)
- Performance testing (Lighthouse, WebPageTest)
- Security scan
- Broken link check
- Form testing (validation, submission)
- Search functionality
- Print styles
Post-Launch
- Monitor analytics
- Check error logs
- Review user feedback
- Test critical user paths
- Verify backups
- Check SSL certificate
Compliance Requirements
Required Pages
Every federal website should include:
- Privacy Policy
- Accessibility Statement
- FOIA (Freedom of Information Act)
- No FEAR Act Notice
- Contact Information
- Site Map
Legal Requirements
- Section 508: Accessibility compliance
- 21st Century IDEA: Modern, mobile-friendly design
- Privacy Act: Protect user information
- Paperwork Reduction Act: OMB approval for information collection
- Plain Writing Act: Clear, simple language
Continuous Monitoring
Uptime Monitoring:
// uptime-monitor.js
const https = require('https');
const fs = require('fs');
class UptimeMonitor {
constructor(url, interval = 300000) { // 5 minutes default
this.url = url;
this.interval = interval;
this.logFile = 'uptime.log';
}
start() {
console.log(`🔍 Starting uptime monitoring for ${this.url}`);
this.check();
setInterval(() => this.check(), this.interval);
}
check() {
const startTime = Date.now();
https.get(this.url, (res) => {
const responseTime = Date.now() - startTime;
const status = res.statusCode;
const timestamp = new Date().toISOString();
const logEntry = `${timestamp} - Status: ${status}, Response Time: ${responseTime}ms\n`;
if (status >= 200 && status < 400) {
console.log(`✅ ${this.url} is up (${responseTime}ms)`);
} else {
console.log(`❌ ${this.url} returned ${status}`);
this.sendAlert(status, responseTime);
}
fs.appendFileSync(this.logFile, logEntry);
}).on('error', (err) => {
const timestamp = new Date().toISOString();
const logEntry = `${timestamp} - Error: ${err.message}\n`;
console.log(`❌ ${this.url} is down: ${err.message}`);
fs.appendFileSync(this.logFile, logEntry);
this.sendAlert('ERROR', 0);
});
}
sendAlert(status, responseTime) {
// Implement your alerting mechanism
// Email, Slack, PagerDuty, etc.
console.log(`🚨 ALERT: Website issue detected - Status: ${status}`);
}
}
// Start monitoring
if (process.env.MONITOR_URL) {
new UptimeMonitor(process.env.MONITOR_URL).start();
}
Resources & Further Reading
Testing Tools
Accessibility Testing:
- WAVE - Web accessibility evaluation tool
- axe DevTools - Browser extension for accessibility testing
- Lighthouse - Performance and accessibility auditing
- Pa11y - Automated command-line accessibility testing
- Colour Contrast Analyser - Color contrast checking
- NVDA - Free screen reader for Windows
- Accessibility Insights - Microsoft’s accessibility testing tools
Performance Testing:
- WebPageTest - Website performance testing
- GTmetrix - Performance analysis
- Pingdom - Website speed test
- Core Web Vitals - Google’s performance metrics
Security Testing:
- Security Headers - Analyze HTTP security headers
- SSL Labs - SSL configuration testing
- OWASP ZAP - Security vulnerability scanner
Code Quality:
- HTML Validator - W3C markup validation
- CSS Validator - W3C CSS validation
- ESLint - JavaScript code analysis
- Stylelint - CSS/SCSS linting
Guidelines & Standards
Federal Requirements:
- Section 508 Standards - Federal accessibility requirements
- 21st Century IDEA - Modern government website requirements
- Plain Language Guidelines - Clear communication standards
- OMB Memoranda - Federal policy directives
Design & Development:
- USWDS Documentation - Complete design system guide
- USWDS Components - Component library
- USWDS Design Tokens - Design system variables
- Web Content Accessibility Guidelines (WCAG) 2.1 - Accessibility standards
Content Strategy:
- Digital.gov Content Guide - Government content best practices
- 18F Content Guide - Writing and content strategy
- usability.gov - User experience best practices
Communities & Support
Government Communities:
- USWDS Community - Design system community
- Digital.gov Communities - Government digital communities
- Section 508 Community - Federal accessibility community
- Government UX Community - User experience practitioners
Technical Support:
- USWDS GitHub - Report issues and contribute
- 11ty Community - Static site generator support
- Federal Front End Guild - Federal developers community
Training & Education:
- Digital.gov Training - Government digital training events
- Section 508 Training - Accessibility training resources
- DigitalGov University - Online training platform
- Web Accessibility Initiative (WAI) - Accessibility courses
Emergency Contacts & Support
Technical Issues:
- USWDS Support: GitHub Issues
- 11ty Support: Community Discord
- Accessibility Help: WebAIM Contact
Compliance Questions:
- Section 508: section.508@gsa.gov
- Plain Language: plainlanguage@gsa.gov
- Digital Analytics Program: dap@support.digitalgov.gov
Quick Reference Card
Print or bookmark this quick reference for daily use:
Before Publishing Content:
- Accessibility: Alt text, headings, color contrast
- Plain language: Short sentences, common words
- Mobile friendly: Test on phone/tablet
- Links work: Check all internal and external links
- Forms tested: Validation and error messages
- Performance: Images optimized, page loads quickly
Monthly Maintenance:
- Content review and updates
- Accessibility scan
- Performance check
- Security updates
- Analytics review
- User feedback assessment
Emergency Response:
- Site Down: Check hosting, DNS, SSL certificate
- Accessibility Issue: Fix immediately, document for future
- Security Alert: Apply patches, notify IT security team
- Broken Feature: Disable if necessary, fix quickly
Following these best practices ensures your website serves all users effectively while meeting federal requirements and standards.