A comprehensive reference for Vercel design principles and best practices. Use this skill when building web applications to ensure:
- UI Excellence - Clear, intuitive, and accessible user interfaces
- Performance - Fast, responsive user experience
- Internationalization - Locale and language friendly
- Accessibility - WCAG compliant and screen reader support
- Consistent Design - Coherent visual language and interactions
Quick Reference
Navigation
- UI Guidelines
- Internationalization
- Forms
- Performance
- Visual Design
- Copywriting
UI Guidelines
Anchors and Navigation
Set scroll-margin-top for headings to link to sections:
h2, h3, h4 {
scroll-margin-top: 1rem;
}
User-Generated Content
Be resilient to user-generated content. Layouts should handle short, average, and very long content.
Accessibility
Accessible content:
- Set accurate names (
aria-label) - Hide decorations (
aria-hidden) - Inaccessibility treeverify
Icon-only buttons need names:
<button aria-label="关闭模态框">×</button>
Semantics over ARIA: Prefer native elements (button、a、label、table) before using aria-*。
Headings and skip links: Use hierarchical <h1–h6> and a "skip to content" link.
Use non-breaking spaces for glued terms: Use to keep units, shortcuts, and names together:
10 MB→10 MB⌘ + K→⌘ + KVercel SDK→Vercel SDK- Use
⁠
Brand Assets
Get brand assets from the logo: Right-click the navigation logo for quick access to brand assets.
Internationalization
Language and Locale
Locale-aware formatting: Format dates, times, numbers, separators, and currency according to the user's locale.
Prefer language settings over location: Detect language via the Accept-Language header and navigator.languages . Never rely on IP/GPS to determine language.
Date/Time Formatting
Use locale-aware formatters:
// JavaScript
const date = new Date(2024, 0, 15);
date.toLocaleDateString('zh-CN', {
year: 'numeric',
month: 'long',
day: 'numeric'
});
// → "2024年1月15日"
date.toLocaleTimeString('zh-CN', {
hour: 'numeric',
minute: '2-digit'
});
// → "上午9:00"
Numbers and Currency
Consistent currency formatting: In any given context, currency should display with 0 or 2 decimal places, do not mix.
// 一致的 0 位小数
¥50
// 一致的 2 位小数
¥50.00
// 不要在同一上下文中混用:¥50 和 ¥50.00
Separate numbers and units with a space:
10 MB(not10MB)- Use non-breaking spaces:
10 MB
Forms
Keyboard Interaction
Enter to submit: When a text input is focused, if it is the only control, Enter submits. If there are multiple controls, apply this rule to the last control.
Textarea behavior: In <textarea> , ⌘/⌃+Enter submits; Enter inserts a new line.
Labels
Labels everywhere: Every control has <label> or associated with a label to support assistive technology.
// 显式标签
<label>
电子邮箱
<input type="email" name="email" />
</label>
// 隐式关联
<label for="email">电子邮箱</label>
<input id="email" type="email" name="email" />
Label activation: Clicking <label> focuses the associated control.
Submit
Submit rules: Keep the submit button enabled before submission begins; then disable it while the request is in progress, show a loading indicator, and include an idempotency key.
Do not pre-disable submit: Allow submitting an incomplete form to show validation feedback.
Unsaved changes: Warn the user before navigating when data may be lost.
Validation
Do not block input: Even if a field only accepts numbers, allow any input and show validation feedback. Blocking keystrokes entirely is confusing because the user cannot get an explanation.
Error placement: Show errors next to the field; on submit, focus the first error.
Input best practices
Autocomplete and name: Set autocomplete and a meaningful name value to enable autofill.
<input type="email" name="email" autocomplete="email" />
<input type="tel" name="phone" autocomplete="tel" />
<input type="text" name="username" autocomplete="username" />
Selective spellcheck: Disable it for email, code, usernames, etc.
<input type="email" name="email" spellcheck="false" />
Correct types and input modes: Use the correct type and inputmode for a better keyboard and validation.
<input type="email" inputmode="email" />
<input type="tel" inputmode="tel" />
<input type="number" inputmode="numeric" />
Placeholders indicate empty: End with an ellipsis.
<input placeholder="请输入您的电子邮箱..." />
Placeholder values: Set placeholders to example values or patterns:
+1 (123) 456-7890sk-012345679…
Controls and click areas
No dead zones on controls: Checkboxes and radio buttons avoid dead zones; the label and control share a generous click target.
Windows <select> Background: Explicitly set <select> and background-color on native color to avoid dark mode contrast bugs on Windows.
Authentication fields
Password managers and 2FA: Ensure compatibility and allow pasting one-time verification codes.
Do not trigger password managers for non-authentication fields: For inputs such as "search", avoid reserved names (e.g. password) and use autocomplete="off" or a specific marker such as autocomplete="one-time-code" for OTP fields.
Text replacement and expansion: Some input methods add trailing spaces. Inputs should trim values to avoid displaying confusing error messages.
Performance
Testing and measurement
Device/browser matrix: Test iOS Low Power Mode and macOS Safari.
Reliable measurement: Disable extensions that add overhead or change runtime behavior.
Track re-renders: Minimize and speed up re-renders. Use React DevTools or React Scan。
Limit when profiling: Test with CPU and network throttling.
Layout and rendering
Minimize layout work: Batch reads/writes; avoid unnecessary reflows/repaints.
Network latency budget: POST/PATCH/DELETE Complete within <500ms.
Keystroke cost: Prefer uncontrolled inputs; keep controlled loops cheap.
Lists and large content
Large lists: Virtualize long lists (e.g. virtua or content-visibility: auto)。
Images and media
Smart preloading: only preload above-the-fold images; lazy-load the rest.
CLS from no images: set explicit image dimensions and reserve space.
<img
src="hero.jpg"
alt="Hero 图像"
width="800"
height="400"
loading="lazy"
/>
Preconnect to origins: use <link rel="preconnect"> to connect resource/CDN domains (with crossorigin when needed) to reduce DNS/TLS latency.
<link rel="preconnect" href="https://cdn.example.com" />
<link rel="preconnect" href="https://cdn.example.com" crossorigin />
Fonts
Preload fonts: for critical text to avoid flicker and layout shift.
<link rel="preload" href="/fonts/inter-var.woff2" as="font" type="font/woff2" crossorigin />
Subset fonts: send only the code points/scripts you use via unicode-range (limit variable axes to what you need) to reduce size.
@font-face {
font-family: 'Inter';
src: url('/fonts/inter-var.woff2') format('woff2');
unicode-range: U+0000-00FF;
}
Workers
Don't use the main thread for expensive work: move especially long tasks to Web Workers to avoid blocking page interactivity.
// main.js
const worker = new Worker('expensive-task.js');
worker.postMessage({ data: largeDataset });
worker.onmessage = (event) => {
console.log('结果:', event.data);
};
Visual design
Shadows
Layered shadows: use at least two layers to simulate ambient and direct light.
box-shadow:
0 1px 1px rgba(0, 0, 0, 0.05),
0 4px 6px rgba(0, 0, 0, 0.1);
Borders
Crisp borders: combine borders and shadows; semi-transparent borders improve edge clarity.
border: 1px solid rgba(0, 0, 0, 0.1);
Border radius
Nested radiuses: child radius ≤ parent radius and concentric so the curves align.
.card {
border-radius: 12px;
}
.card .button {
border-radius: 8px; /* ≤ 12px */
}
Color
Hue consistency: on non-neutral backgrounds, tint borders/shadows/text toward the same hue.
.surface-blue {
border-color: rgba(59, 130, 246, 0.2);
box-shadow: 0 2px 8px rgba(59, 130, 246, 0.15);
}
Accessible charts: use colorblind-friendly palettes.
Minimum contrast: prefer APCA over WCAG 2 for more accurate perceived contrast.
Interactions increase contrast: :hover、:active、:focus have more contrast than the resting state.
button {
background: #2563eb;
}
button:hover {
background: #1d4ed8; /* 更深以增加对比度 */
}
button:focus {
outline: 2px solid #000;
outline-offset: 2px;
}
Browser integration
Browser UI matches your background: set <meta name="theme-color" content="#000000"> to align the browser's theme color with the page background.
<meta name="theme-color" content="#000000" media="(prefers-color-scheme: dark)" />
Set an appropriate color-scheme: in a dark theme, set <html> for the color-scheme: darktag so scrollbars and other device UI have appropriate contrast.
:root {
color-scheme: light dark;
}
Typography
Text antialiasing and transforms: scaling text may change smoothness. Prefer animating a wrapper rather than text nodes. If artifacts persist, set translateZ(0) or will-change: transform to promote it to its own layer.
.scale-wrapper {
transform: scale(1.1);
will-change: transform;
}
Gradients
Avoid gradient banding: some colors and display types will have color banding. You can use a mask instead.
Copywriting
Tone and voice
Active voice:
- ❌ "The CLI will be installed"
- ✅ "Install the CLI"
Use title case for headings and buttons(Chicago). On marketing pages, use sentence case.
Clear and concise: use as few words as possible.
Prefer & over and。
Action-oriented language:
- ❌ "You will need the CLI…"
- ✅ "Install the CLI…"
Keep nouns consistent: Introduce as few unique terms as possible.
Use second person: Avoid first person.
Placeholders and examples
Use consistent placeholders:
- Strings:
YOUR_API_TOKEN_HERE - Numbers:
0123456789
Numbers and measurements
Use digits for counts:
- ❌ "eight deployments"
- ✅ "8 deployments"
Separate numbers and units with a space:
- ❌
10MB - ✅
10 MB - Use non-breaking spaces:
10 MB
Error messages
Default to positive language: Phrase messages in an encouraging and problem-solving way, even for error messages.
- ❌ "Your deployment failed"
- ✅ "Something went wrong—please try again or contact support."
Error messages guide the exit: Don't just state what went wrong—tell users how to fix it.
- ❌ "Invalid API key"
- ✅ "Your API key is incorrect or expired. Generate a new key in your account settings."
Copy and buttons/links should educate and provide a clear action.
Clarity
Avoid ambiguity: Labels are clear and specific.
- ❌ Button label "Continue"
- ✅ "Save API key"
Resources
- Vercel Design Guidelines
- Chrome accessibility tree
- APCA contrast
- React DevTools
- React Scan
- Virtua virtualization
- Web Workers API
- Title case converter
Usage examples
Build forms
- Use the correct input types and autocomplete attributes
- Add labels for all controls
- Handle keyboard interactions (Enter to submit)
- Don't block input; show validation feedback
- Show errors next to the field
- Disable submit during submission and show a loading indicator
Optimize performance
- Set explicit image dimensions
- Preload above-the-fold content
- Lazy-load images below the fold
- Preconnect to CDN origins
- Use Web Workers for expensive operations
- Virtualize large lists
Improve accessibility
- Use semantic HTML elements
- Add ARIA labels for icon-only buttons
- Set an appropriate heading hierarchy
- Add skip-to-content links
- Ensure sufficient color contrast
- Test with screen readers
Internationalization
- Detect language via the Accept-Language header
- Format dates/numbers/currency for the user's locale
- Use non-breaking spaces for glued terms
- Don't rely on IP/GPS for language detection