web-design-guidelines
Skill30 starsChanged 53 days agoMITView on GitHub
Web design best practices, accessibility, responsive layout, color contrast. Use when auditing a UI for a11y compliance, designing responsive layouts, or establishing design standards across a web app.
- Installs packages
176 other projects use a version of this.
Adopted by
Most recently taken up by
- yuiseki/GeoAI-master-skillstheir own version, first seen Nov 8, 2026
- open-slide/open-slidetheir own version, first seen Nov 8, 2026
- arch3rPro/Skills-Spacetheir own version, first seen Nov 8, 2026
- alunadev/ald-skillstheir own version, first seen Nov 8, 2026
- Contentrain/studiotheir own version, first seen Nov 8, 2026
- eea/eea.agent.skillstheir own version, first seen Nov 8, 2026
Used with
Projects with it also use canvas-procedural-animation, intelligent-routing and 10 more.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
LinHao-citySkillcanvas-procedural-animation
Use p5.js/canvas for local procedural character effects: particles, weather, squash/stretch, walk cycles, and environmental motion.
Also in 5 projects that use this
SKB3002Skillintelligent-routing
Automatic agent selection and intelligent task routing. Analyzes user requests and automatically selects the best specialist agent(s) without requiring explicit user mentions.
Also in 5 projects that use this
VercelSkillvercel-optimize
Use for Vercel cost and performance optimization on deployed projects, especially Next.js, SvelteKit, Nuxt, and limited Astro apps. Collect Vercel metrics, usage, project config, and code scan results first; investigate only metric-backed candidates; produce ranked recommendations grounded in verified files and version-aware Vercel/framework docs. Trigger for Vercel bill reduction, slow or expensive routes, caching opportunities, Function Invocations, Build Minutes, Fast Data Transfer, Core Web Vitals, Bot Management, Fluid compute, or cost breakdown requests.
Also in 15 projects that use this
thongdn-itSkillnuqs
nuqs (type-safe URL query state) best practices for Next.js applications. This skill should be used when writing, reviewing, or refactoring code that uses nuqs for URL state management. Triggers on tasks involving useQueryState, useQueryStates, search params, URL state, query parameters, nuqs parsers, or Next.js routing with state.
Also in 4 projects that use this
LinHao-citySkillpose-library-design
Design reusable 2D character pose libraries, action cycles, and expression states for data-driven animation.
Also in 4 projects that use this
stophobiaSkillsurprise-me
Create a delightful, unexpected "wow" experience for the user by dynamically discovering and creatively combining other enabled skills. Triggers when the user says "surprise me" or any request expressing a desire for an unexpected creative showcase. Also triggers when the user is bored, wants inspiration, or asks for "something interesting".
Also in 4 projects that use this
- +2 more from LinHao-city
Other versions176 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 176
- bytedance/deer-flow★ 85ksame name
- calesthio/OpenMontage★ 78ksame name
- OpenMontageInc/OpenMontage★ 78ksame name
- multica-ai/multica★ 55ksame name
- moeru-ai/airi★ 51ksame name
- vercel-labs/agent-skills★ 33ksame name
- awesome-dsh-plugin/awesome-dsh-plugin★ 24ksame name
- open-metadata/OpenMetadata★ 16ksame name
- trycompai/crm★ 12ksame name
- mengxi-ream/read-frog★ 10ksame name
166 more not listed
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository30 other files it gives its agents.
- AGENTS.mdAGENTS.md
- claude/CLAUDE.mdCLAUDE.md
- llms.txtllms.txt
- api-design-patternsSkill
- auth-patternsSkill
- backend-dev-guidelinesSkill
- brainstormingSkill
- code-review-patternsSkill
- deployment-guideSkill
- docker-patternsSkill
- docx-officialSkill
- frontend-designSkill
- github-actionsSkill
- git-workflowSkill
- nestjs-patternsSkill
- nextjs-app-routerSkill
- pdf-officialSkill
- pptx-officialSkill
- prisma-workflowSkill
- prompt-engineeringSkill
- react-best-practicesSkill
- security-checklistSkill
- skill-creatorSkill
- software-architectureSkill
- systematic-debuggingSkill
- tailwind-patternsSkill
- test-driven-developmentSkill
- typescript-patternsSkill
- webapp-testingSkill
- xlsx-officialSkill
The file
We split this skill into the rules it gives an agent
8 rules. 0 are common, 3 are distinctive, and 5 are very specific to this project.
0
Common
Most of the 173 edited versions we read keep these.
3
Distinctive
This author's own choices. Worth a look.
5
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 367
Never remove outline on focus without providing an equivalent visual indicator
- Distinctive: line 368
Never use color alone to convey information (add icons, text, or patterns)
- Very specific: line 369
Never set font-size below 14px (16px minimum for body text)
- Very specific: line 370
Never use placeholder as a label substitute — placeholders disappear on input
- Very specific: line 371
Never disable zoom (user-scalable=no) — breaks accessibility for low-vision users
- Very specific: line 372
Never use tabindex values > 0 — they break the natural tab order
- Distinctive: line 373
Never let hover-only tooltips carry essential information (mobile has no hover)
- Distinctive: line 374
Never auto-play audio or video with sound without user consent
“Common” is measured: kept by at least 6 in 10 of the 173 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Web Design Guidelines
Accessibility (WCAG 2.1 AA)
Color Contrast Requirements
- Normal text (< 18pt): minimum 4.5:1 contrast ratio
- Large text (≥ 18pt or 14pt bold): minimum 3:1
- UI components and graphical objects: minimum 3:1
// Use a utility to check contrast at runtime in dev
// Install: npm i color2k
import { parseToRgb, getLuminance } from 'color2k'
function getContrastRatio(fg: string, bg: string): number {
const l1 = getLuminance(fg)
const l2 = getLuminance(bg)
const lighter = Math.max(l1, l2)
const darker = Math.min(l1, l2)
return (lighter + 0.05) / (darker + 0.05)
}
// In Storybook stories or tests:
// expect(getContrastRatio('#2563eb', '#ffffff')).toBeGreaterThan(4.5)Semantic HTML
// Good: semantic structure
export function PageLayout() {
return (
<>
<header role="banner">
<nav aria-label="Main navigation">
<ul role="list">
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
</header>
<main id="main-content" tabIndex={-1}>
<h1>Page Title</h1>
{/* Skip-to-main link target */}
</main>
<aside aria-label="Related content">
{/* Sidebar */}
</aside>
<footer role="contentinfo">
{/* Footer */}
</footer>
</>
)
}
// Skip link — must be the very first focusable element
function SkipToMain() {
return (
<a
href="#main-content"
className="sr-only focus:not-sr-only focus:absolute focus:top-4 focus:left-4 focus:z-50 focus:px-4 focus:py-2 focus:bg-white focus:text-blue-600 focus:rounded-lg focus:shadow-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
>
Skip to main content
</a>
)
}Keyboard Navigation
// All interactive elements must be keyboard-operable
function DropdownMenu({ items }: { items: MenuItem[] }) {
const [open, setOpen] = React.useState(false)
const [activeIndex, setActiveIndex] = React.useState(-1)
const handleKeyDown = (e: React.KeyboardEvent) => {
switch (e.key) {
case 'ArrowDown':
e.preventDefault()
setActiveIndex(i => Math.min(i + 1, items.length - 1))
break
case 'ArrowUp':
e.preventDefault()
setActiveIndex(i => Math.max(i - 1, 0))
break
case 'Escape':
setOpen(false)
break
case 'Enter':
case ' ':
if (activeIndex >= 0) items[activeIndex].action()
break
}
}
return (
<div role="navigation" aria-label="Actions menu">
<button
aria-haspopup="true"
aria-expanded={open}
onClick={() => setOpen(o => !o)}
>
Actions
</button>
{open && (
<ul
role="menu"
onKeyDown={handleKeyDown}
className="..."
>
{items.map((item, i) => (
<li key={item.id} role="menuitem" tabIndex={i === activeIndex ? 0 : -1}>
<button onClick={item.action}>{item.label}</button>
</li>
))}
</ul>
)}
</div>
)
}ARIA Labels
// Always label icon-only buttons
<button aria-label="Close dialog" onClick={onClose}>
<XIcon aria-hidden="true" className="h-5 w-5" />
</button>
// Images
<img src={product.image} alt={`${product.name} — front view`} />
// Decorative images get empty alt
<img src="/divider.svg" alt="" role="presentation" />
// Live regions for dynamic content
<div aria-live="polite" aria-atomic="true" className="sr-only">
{statusMessage}
</div>Responsive Layout
Mobile-First Approach
/* Write base styles for mobile, then progressively enhance */
.card {
padding: 1rem; /* mobile */
}
@media (min-width: 640px) { /* sm */
.card { padding: 1.5rem; }
}
@media (min-width: 1024px) { /* lg */
.card { padding: 2rem; }
}// Tailwind mobile-first
<div className="px-4 sm:px-6 lg:px-8">
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
{items.map(item => <Item key={item.id} {...item} />)}
</div>
</div>Fluid Typography
/* clamp(min, preferred, max) — scales smoothly between viewport sizes */
:root {
--text-base: clamp(1rem, 0.9rem + 0.5vw, 1.125rem);
--text-lg: clamp(1.125rem, 1rem + 0.75vw, 1.375rem);
--text-xl: clamp(1.25rem, 1rem + 1.5vw, 1.75rem);
--text-2xl: clamp(1.5rem, 1rem + 2.5vw, 2.25rem);
--text-4xl: clamp(2rem, 1rem + 5vw, 4rem);
}Container Queries
/* Style based on parent width, not viewport width */
.card-grid {
container-type: inline-size;
container-name: card-grid;
}
@container card-grid (min-width: 480px) {
.product-card {
display: grid;
grid-template-columns: 140px 1fr;
}
}Image Optimization
// Next.js Image — always use this over <img>
import Image from 'next/image'
// Known dimensions (static assets)
<Image
src="/hero.jpg"
alt="Dashboard overview showing key metrics"
width={1200}
height={630}
priority // LCP image: load eagerly
className="rounded-xl object-cover"
/>
// Unknown dimensions (user uploads)
<div className="relative aspect-video w-full overflow-hidden rounded-xl">
<Image
src={user.avatar}
alt={`${user.name}'s profile photo`}
fill
sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw"
className="object-cover"
/>
</div>Touch Targets
Minimum touch target size: 44×44 px (Apple HIG) / 48×48 dp (Material).
// Expand click area without changing visual size
<button
className="
relative p-2 -m-2
/* visual size stays 24px, but hit area is 44px (24 + 2*8 = 40... close enough) */
before:absolute before:inset-0 before:-m-2
"
>
<MenuIcon className="h-6 w-6" />
</button>
// Or just give buttons adequate padding
<button className="min-h-[44px] min-w-[44px] px-4 py-2.5">
Submit
</button>Focus Management
// Trap focus inside modals
import { useEffect, useRef } from 'react'
function useFocusTrap(active: boolean) {
const containerRef = useRef<HTMLDivElement>(null)
useEffect(() => {
if (!active || !containerRef.current) return
const focusable = containerRef.current.querySelectorAll<HTMLElement>(
'a[href], button:not([disabled]), input:not([disabled]), select, textarea, [tabindex]:not([tabindex="-1"])'
)
const first = focusable[0]
const last = focusable[focusable.length - 1]
first?.focus()
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key !== 'Tab') return
if (e.shiftKey) {
if (document.activeElement === first) {
e.preventDefault()
last?.focus()
}
} else {
if (document.activeElement === last) {
e.preventDefault()
first?.focus()
}
}
}
document.addEventListener('keydown', handleKeyDown)
return () => document.removeEventListener('keydown', handleKeyDown)
}, [active])
return containerRef
}Performance
Core Web Vitals Targets
| Metric | Good | Needs Improvement |
| LCP (Largest Contentful Paint) | < 2.5s | 2.5–4.0s |
| INP (Interaction to Next Paint) | < 200ms | 200–500ms |
| CLS (Cumulative Layout Shift) | < 0.1 | 0.1–0.25 |
// Prevent CLS: always reserve space for images/embeds
<div className="aspect-video w-full bg-gray-100 rounded-xl overflow-hidden">
<Image src={src} alt={alt} fill className="object-cover" />
</div>
// Prevent CLS: skeleton loaders match exact dimensions
function SkeletonCard() {
return (
<div className="rounded-xl border border-gray-100 p-6 animate-pulse">
<div className="h-6 bg-gray-200 rounded w-3/4 mb-3" />
<div className="h-4 bg-gray-200 rounded w-full mb-2" />
<div className="h-4 bg-gray-200 rounded w-5/6" />
</div>
)
}Dark Mode
// tailwind.config.ts
const config = {
darkMode: 'class', // Toggle via class on <html>
theme: {
extend: {
colors: {
background: 'hsl(var(--background))',
foreground: 'hsl(var(--foreground))',
},
},
},
}
// globals.css
// :root {
// --background: 0 0% 100%;
// --foreground: 222 47% 11%;
// }
// .dark {
// --background: 222 47% 4%;
// --foreground: 210 40% 98%;
// }
// Toggle hook
function useDarkMode() {
const [dark, setDark] = React.useState(() =>
window.matchMedia('(prefers-color-scheme: dark)').matches
)
useEffect(() => {
document.documentElement.classList.toggle('dark', dark)
localStorage.setItem('theme', dark ? 'dark' : 'light')
}, [dark])
return { dark, toggle: () => setDark(d => !d) }
}Forbidden Patterns
- Never remove
outlineon focus without providing an equivalent visual indicator - Never use color alone to convey information (add icons, text, or patterns)
- Never set
font-sizebelow 14px (16px minimum for body text) - Never use
placeholderas a label substitute — placeholders disappear on input - Never disable zoom (
user-scalable=no) — breaks accessibility for low-vision users - Never use
tabindexvalues > 0 — they break the natural tab order - Never let hover-only tooltips carry essential information (mobile has no hover)
- Never auto-play audio or video with sound without user consent
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

