Every designer knows that choosing a color palette is hard. But choosing which colors text should be β across headings, body copy, links, captions, and UI labels β is arguably harder. Get it right and your content flows effortlessly from the page to the reader's brain. Get it wrong and even the most brilliant copy becomes unreadable noise.
In this comprehensive guide, you'll learn the art and science of text color design: how to build a complete typographic color system that balances readability, hierarchy, emotion, and accessibility β across every screen size and lighting condition.
Color is the first thing the brain registers when looking at text β even before the shapes of the letters themselves. Studies in reading psychology show that color contrast accounts for up to 80% of reading comfort, while typographic color (hue and intensity) directly affects reading speed, comprehension, and eye fatigue.
Consider this: two identical paragraphs, set in the same font at the same size, will feel completely different when one is set in #333 on white and the other in #999 on white. The brain works harder to decode low-contrast text, consuming cognitive resources that should be going toward comprehension. This is called the cognitive load of readability, and it's one of the most overlooked factors in design.
Text color isn't just about aesthetics β it's about cognitive ergonomics. Every typographic color decision either helps or hinders the reader's ability to absorb information. Master this, and your designs become fundamentally more effective.
A professional text color system is more than "black text, blue links." Modern design systems define 5β7 distinct text color roles, each with a specific purpose and visual weight:
| Role | Typical Weight | Purpose | Example (light bg) |
|---|---|---|---|
| Primary / Body | Highest | Main content, paragraphs, running text | #1a1a2e β near-black |
| Secondary | Medium-high | Subtitles, metadata, secondary nav | #3a3a4a β dark gray |
| Tertiary / Muted | Medium | Captions, footnotes, timestamps | #6a6a7a β mid gray |
| Placeholder | Low | Form placeholder text, disabled content | #9a9aaa β light gray |
| Headings | Highest | Article and section titles | #111122 β black-blue |
| Links | Accent | Interactive text, navigational elements | #5a3c9a β branded purple |
| Emphasis | Variable | Highlighted words, inline code, stats | #d44c4c or accent color |
The key insight: text colors should be defined by role, not by value. Instead of always using #333 for text, define a "body" token that maps to different values in light mode vs dark mode, or on different background colors. This is the foundation of scalable, maintainable typographic color.
Text readability isn't determined by contrast alone β it's the interplay between three variables. Understanding this relationship is what separates professional type color from amateur choices.
WCAG 2.2 defines clear minimums that should be your starting point, not your ceiling:
But here's the nuance most guides miss: perceived contrast differs from measured contrast. On an Apple Retina display in a well-lit room, #555 on white (ratio ~5:1) may feel comfortable. On a low-brightness LCD under sunlight, the same ratio feels illegible. Always test your text colors on the worst-case screen your audience might use.
Font weight directly affects how much contrast you need. A 300-weight light text needs significantly more contrast than an 800-weight bold text at the same size. This is the weight-contrast tradeoff:
When you choose a fine or light font family β like Helvetica Neue Light or Inter Thin β you're committing to much stricter contrast requirements. Many designers draw thin text in gray to achieve a "refined" look, only to discover it's borderline illegible on less-than-perfect screens. The fix: use a lighter weight (e.g., 400 instead of 700) but keep the color dark (#1a1a2e range), rather than washing out the color itself.
Your typographic scale β the set of font sizes you use β should dictate how you apply color. The general principle: the smaller the text, the higher the contrast should be.
#2a2a3a to #3a3a4a) can work if the font weight is 400+.Now let's turn theory into practice. Here's how to build a complete, production-ready semantic text color palette from scratch.
Your text colors are relative to your background colors. Before choosing text colors, define your backgrounds:
#ffffff) or near-white (#f8f9fc)#1a1a2e), deep gray (#2a2a3a)Using a brand-nearest-black value as your starting point, step down through lighter neutrals. Here's a proven light-mode palette:
/* Brand-aware near-blacks for text */
--color-text-primary: #1a1a2e; /* Slight blue tint β brand-aware */
--color-text-secondary: #3a3a4a; /* Perceptually balanced midpoint */
--color-text-tertiary: #6a6a7a; /* For captions and metadata */
--color-text-placeholder: #9a9aaa; /* Input placeholder only */
--color-text-disabled: #b0b0bb; /* Clearly disabled state */
--color-text-inverse: #ffffff; /* Text on dark backgrounds */
--color-text-link: #5a3c9a; /* Brand accent β meets 4.5:1 on white */
--color-text-link-hover: #3a1a7a; /* Darker for hover state */
For dark mode, invert the logic:
/* Dark mode text colors */
--color-text-primary: #e8e0f0; /* Near-white with slight purple cast */
--color-text-secondary: #b8b0c8; /* Muted light gray */
--color-text-tertiary: #8a8098; /* For captions */
--color-text-placeholder: #6a5a78; /* Input placeholder */
--color-text-link: #b8a0e0; /* Lighter link on dark bg */
--color-text-link-hover: #d0c0f0;
Every text color must be tested against every possible background it can appear on. The most common failure point is secondary text on colored surfaces. A #6a6a7a secondary text may pass WCAG AA on white (ratio ~5.5:1) but fail on a light brand-tinted surface (ratio may drop to 3:1 or lower).
Create a contrast matrix β a spreadsheet that cross-references every text color token with every background token. If any pairing fails WCAG AA for the intended text size, adjust until it passes. This is tedious work the first time, but it prevents every accessibility bug downstream.
Link colors deserve special attention because they serve a dual purpose: they must be visually distinct from body text and accessible at the same time.
The web's convention of blue underlined links (#0000EE β the original HTML blue) exists for good reason: it works. Blue is almost never used for body text, so it creates immediate visual distinction. But that raw HTML blue (#0000EE) has a contrast ratio of only ~4.1:1 on white β barely passing AA for body text and failing for small text.
Better link blues include:
#1a5a8a β Slightly muted navy blue (5.5:1 on white)#2a6aaa β Richer medium blue (5.2:1 on white)#5a3c9a β Purple-blue brand tone (5.8:1 on white)#1a7a6a β Teal alternative (5.3:1 on white)WCAG 2.2 requires that links be distinguishable by more than color alone β a non-color indicator (underline, icon, bold weight) must be present for users with color vision deficiencies. The exception: if the link appears in a block of text where context makes it unambiguous, and the contrast ratio against surrounding text is at least 3:1.
Best practice: always underline links in body text. Reserve color-only differentiation for navigation menus, cards, and UI elements where the surrounding design provides sufficient context.
A complete link color system includes four states:
--color-link-default: #2a6aaa;
--color-link-hover: #1a4a7a;
--color-link-active: #0a2a5a;
--color-link-visited: #6a4a8a;
Placing text on colored backgrounds β whether cards, banners, buttons, or hero sections β introduces a unique set of challenges.
When placing light text on a dark background, the natural instinct is to use pure white (#ffffff). But pure white on a deep color can cause halation β the visual effect where bright text seems to "bleed" into the dark background, creating eye fatigue over long reading sessions.
Better approach: tint your white text with a hint of the background's complementary color or a warm/cool shift:
#e0ecf8 (white-blue tint)#e8e0f0 (white-purple tint)#e0f0ec (white-teal tint)#e8e8ea (warm off-white)These tinted whites feel brighter than pure white against their respective backgrounds because the slight hue shift reduces simultaneous contrast β the visual phenomenon where the brain exaggerates differences between adjacent colors.
For dark text on pastel or light brand backgrounds, avoid pure black (#000000). Instead, use the background color's darkest shade as your text color:
#e8e0f8): use deep purple text (#2a1a4a)#fce8e8): use deep burgundy text (#4a2020)#e0f0e8): use deep forest text (#1a3a2a)This creates a monochromatic harmony β the text feels like it belongs to the background because it shares the same hue family β while maintaining high contrast.
The most effective typographic systems use color, weight, and size together to create a clear visual hierarchy β a roadmap that guides the reader's eye from most to least important content:
| Level | Example Element | Size | Weight | Color |
|---|---|---|---|---|
| 1 β Hero | Page title (H1) | 48px+ | 700β900 | Primary near-black or brand color |
| 2 β Section | Section heading (H2) | 28β36px | 600β700 | Primary or near-brand |
| 3 β Subsection | Subheading (H3) | 20β24px | 500β600 | Primary or secondary |
| 4 β Body | Paragraph (p) | 16β18px | 400 | Primary or secondary |
| 5 β Meta | Date, category, caption | 13β14px | 400 | Tertiary |
A common mistake: using too many hierarchy levels. If you have H1 through H6 all with different colors and sizes, you've created 6 distinct visual stops β but the human brain can only hold about 3β4 levels in working memory. Simplify to no more than 4 color-defined levels plus a link state.
One of the best examples of text color design in production is The New York Times digital reading experience. Their system demonstrates how subtle color choices create a premium reading experience:
#333333 on off-white (#faf9f7) β a warm, paper-like contrast that reduces glare compared to pure white backgrounds#121212) β the highest contrast to command maximum attention#808080 β clearly secondary but still readable#56758f β a muted, desaturated blue that differentiates without competing with the text#b53a25 β their signature red, used sparingly for section labelsThe result: a typographic color system that feels authoritative yet unhurried. The red kickers provide just enough visual excitement to signal importance, while the muted link blue ensures in-article navigation never breaks the reading flow.
Stripe's developer documentation is renowned for its clarity. Their text color system for documentation reveals another excellent approach:
#1a1a2e β near-black with a subtle blue undertone matching their brand#b91a5c β a vivid rose that pops against the text but doesn't overwhelm#1e7a8a β a teal-blue that's unique within the palette#5a5a6a β muted for helper text and table contentWhat makes Stripe's system effective: they use two distinct accent colors β rose for code and teal for links β which prevents confusion between interactive and semantic highlighting. This is a pro-level pattern: never use the same color for different semantic purposes.
Dark mode isn't just "invert the colors." Text color design for dark surfaces requires fundamentally different thinking:
On dark backgrounds, highly saturated colors "vibrate" against the dark, creating visual stress. Reduce saturation by 30β50% for text on dark backgrounds compared to the same role on light backgrounds. A link that's #5a3c9a on white should become #b8a0e0 (much lighter, less saturated) on dark.
Dark mode body text at #e0e0e0 (roughly 90% brightness) is more comfortable than #ffffff (100% brightness). The extra 10% of brightness reduction significantly reduces halation and eye strain without sacrificing readability. Most design systems set dark mode body text at 85β92% brightness.
On dark backgrounds, colors appear brighter and more saturated than they actually are due to the BezoldβBrΓΌcke effect β the eye's perception of hue shifts with luminance. A blue link that looks perfect at noon on a light background may appear neon and garish at night in dark mode. Always test dark mode text colors in a dimly lit environment.
Approximately 8% of men and 0.5% of women have some form of color vision deficiency (CVD). The most common types β deuteranopia (green-blind) and protanopia (red-blind) β directly affect how text colors are perceived.
If you use red text to indicate errors and green text to indicate success, a red-green color-blind user sees them as nearly identical shades. Always pair color with at least one non-color signal: an icon, a bold weight, an underline, or a background pattern.
Before finalizing a text color system, run every pairing through a CVD simulator. Key failure points to check:
The safest strategy for CVD-accessible text color is to differentiate by luminance (lightness) rather than hue. A dark gray (#3a3a4a) and a lighter gray (#8a8a9a) are distinguishable regardless of color vision deficiency β no hue difference required.
Here's a step-by-step workflow for validating your text color system:
| Mistake | Why It Fails | Fix |
|---|---|---|
| Pure black (#000) on pure white (#fff) | Causes excessive eye strain due to max contrast creating halation | Use dark gray (#1a1a2e to #3a3a4a) on off-white for body text |
| Gray text on gray background | Insufficient contrast for comfortable reading | Increase the luminance difference to at least 4.5:1 ratio |
| Color-only link differentiation | Inaccessible for color-blind users | Add underline or another non-color indicator |
| Same color for links and code | Users can't distinguish interactive from semantic | Assign distinct colors to links vs code vs emphasis |
| Too many gray shades | Creates visual noise without meaningful distinction | Limit to 3β4 text color roles, make differences perceivable |
| Colored headings with no hierarchy | Every heading competes for attention equally | Use size and weight for primary hierarchy, color for secondary |
CSS gradient text and animated color effects have become popular in 2026, but they introduce unique accessibility challenges. When using gradient text:
#5a3c9a to #b8a0e0 on a white background will have sections below WCAG AA.prefers-reduced-motion: reduce β your animated text should gracefully degrade to a static solid color.In 2026, AI tools like Claude and ChatGPT can help generate initial text color systems, but the human designer's role in validation and nuance is more important than ever. AI is excellent at generating mathematically correct contrast ratios, but it struggles with:
Use AI to generate the starting palette and automate the contrast matrix, but always apply your own design judgment to the final choices. The best text color systems in 2026 combine computational precision with human empathy.
Color and typography are inseparable partners in great design. A well-designed text color system makes your content effortlessly readable, intuitively hierarchical, and emotionally appropriate β all without the reader ever noticing the choices you made.
The best advice we can give: start simple. Define your four core text roles (primary, secondary, tertiary, link). Test every pairing against your backgrounds. Then add nuance β tinted whites, brand-colored headings, dark mode variants β only after the foundation is solid.
Your readers will never thank you for good text color choices. They'll just keep reading, keep scrolling, and keep engaging. And that's the highest compliment any designer can receive.
Ready to test your text colors? Use the ColorPick color picker tool to check contrast ratios, sample colors from any webpage, and build your perfect text color palette.