Semantik Renk Sistemleri: Renkleri Ton Değil Amaçla Adlandırma
Embed This Widget
Add the script tag and a data attribute to embed this widget.
Embed via iframe for maximum compatibility.
<iframe src="https://colorfyi.com/iframe/entity//" width="420" height="400" frameborder="0" style="border:0;border-radius:10px;max-width:100%" loading="lazy"></iframe>
Paste this URL in WordPress, Medium, or any oEmbed-compatible platform.
https://colorfyi.com/entity//
Add a dynamic SVG badge to your README or docs.
[](https://colorfyi.com/entity//)
Use the native HTML custom element.
A color system that calls its primary button color "blue" works fine until someone changes the brand to green. Now every reference to "blue" is wrong, and every designer and developer who touches the codebase must hunt down instances where "blue" actually means "interactive." Semantic color naming solves this problem at the root: instead of naming a color by what it looks like, you name it by what it does.
This is not a cosmetic distinction. It changes how teams make decisions, how products handle theme changes, and how accessible your UI remains across different modes.
Why Semantic Naming Beats Hue-Based Naming
The Naming Problem in Practice
Most teams start with hue-based names. You have a style guide that says: "Primary: blue-600. Secondary: gray-700. Error: red-500." This feels clean, and for a while it is. The problem surfaces when:
- The brand pivots and the "primary blue" becomes purple
- You add a dark mode where the "error red" must lighten considerably to maintain contrast
- A white-label product needs different brand colors without touching component logic
With hue-based naming, every rebranding is a find-and-replace operation across the codebase. With semantic naming, you change the value of --color-brand-primary in one file, and every component that uses it updates automatically.
Semantic Names Communicate Intent
A variable named --color-interactive-default tells you its job: this color marks things users can interact with. A variable named blue-500 tells you nothing except what it looks like. When a developer sees color: var(--color-text-danger) in a stylesheet, they immediately understand it is danger-state text. When they see color: #EF4444, they have to cross-reference a spec to understand why that particular red was chosen.
Semantic names make code self-documenting. They make design reviews faster because everyone speaks the same language. They make handoffs between designers and developers less error-prone.
Dark Mode Is Semantic by Nature
Dark mode is the clearest argument for semantic systems. In light mode, --color-surface-default might be #FFFFFF. In dark mode, it might be #1E1E1E. The semantic name stays constant; only the value changes. If you built your system around hue names, "white" and "near-black" cannot share a single semantic role — you would need conditional logic everywhere rather than a single token swap.
Primitive vs Semantic Color Tokens
A well-structured color token system has at least two layers: primitive tokens and semantic tokens.
Primitive Tokens: The Color Palette
Primitive tokens are your raw color palette. They have no opinion about where they are used — they simply define every color available in your system. A typical palette might include a neutral scale, a brand scale, and utility scales:
/* Primitive tokens — the full color palette */
--color-blue-50: #EFF6FF;
--color-blue-100: #DBEAFE;
--color-blue-200: #BFDBFE;
--color-blue-300: #93C5FD;
--color-blue-400: #60A5FA;
--color-blue-500: #3B82F6;
--color-blue-600: #2563EB;
--color-blue-700: #1D4ED8;
--color-blue-800: #1E40AF;
--color-blue-900: #1E3A8A;
--color-blue-950: #172554;
--color-green-50: #F0FDF4;
--color-green-500: #22C55E;
--color-green-700: #15803D;
--color-red-50: #FFF1F2;
--color-red-500: #EF4444;
--color-red-700: #B91C1C;
--color-yellow-50: #FEFCE8;
--color-yellow-500: #EAB308;
--color-yellow-700: #A16207;
--color-neutral-0: #FFFFFF;
--color-neutral-50: #F8FAFC;
--color-neutral-100: #F1F5F9;
--color-neutral-200: #E2E8F0;
--color-neutral-900: #0F172A;
--color-neutral-950: #020617;
Primitive tokens are never referenced directly in component code. They exist exclusively as source values for semantic tokens.
Semantic Tokens: Colors With Purpose
Semantic tokens reference primitive tokens and assign them roles:
/* Semantic tokens — what each color does */
:root {
/* Brand */
--color-brand-primary: var(--color-blue-600);
--color-brand-primary-hover: var(--color-blue-700);
--color-brand-primary-subtle: var(--color-blue-50);
/* Text */
--color-text-default: var(--color-neutral-900);
--color-text-muted: var(--color-neutral-500);
--color-text-inverse: var(--color-neutral-0);
--color-text-danger: var(--color-red-700);
--color-text-success: var(--color-green-700);
--color-text-warning: var(--color-yellow-700);
--color-text-info: var(--color-blue-700);
/* Surfaces */
--color-surface-default: var(--color-neutral-0);
--color-surface-subtle: var(--color-neutral-50);
--color-surface-raised: var(--color-neutral-0);
--color-surface-overlay: var(--color-neutral-50);
/* Borders */
--color-border-default: var(--color-neutral-200);
--color-border-focus: var(--color-blue-600);
--color-border-danger: var(--color-red-500);
/* Feedback states */
--color-feedback-danger-surface: var(--color-red-50);
--color-feedback-danger-border: var(--color-red-500);
--color-feedback-danger-text: var(--color-red-700);
--color-feedback-success-surface: var(--color-green-50);
--color-feedback-warning-surface: var(--color-yellow-50);
--color-feedback-info-surface: var(--color-blue-50);
}
Component stylesheets consume only semantic tokens. No primitive colors appear in component code.
Success, Warning, Error, and Info Color Patterns
Feedback colors are the most common starting point for semantic systems because their purpose is undeniable. No one names an error state #EF4444 for its hue — they choose it because it signals danger. Making that intent explicit in the token name is a small step with large payoff.
The Four Feedback Categories
Success communicates positive outcomes: form submission completed, payment processed, file uploaded. Success colors are typically greens, though teal and emerald variations work well. The critical requirement is that the color reads as positive across cultures — this usually means avoiding yellow-greens that can look sickly, and favoring clear, saturated greens.
A useful success trio: - Surface: #F0FDF4 — very light green background for success banners - Border: #22C55E — visible green border for the container - Text: #15803D — darker green for readable text inside
Warning communicates risk that has not yet become an error: approaching a file size limit, a session about to expire, an action with irreversible consequences. Yellows and ambers traditionally signal caution, borrowing from traffic light conventions. Bright yellows fail contrast requirements against white — always pair a yellow background with a dark amber or brown text color.
A warning trio that passes WCAG AA: - Surface: #FEFCE8 — pale yellow background - Border: #EAB308 — visible yellow border - Text: #713F12 — dark amber text (dark enough for sufficient contrast)
Error communicates failure: invalid input, server error, destructive action confirmation. Reds are the near-universal convention. The temptation is to use a single red, but feedback states work better as triads — a light surface, a medium border, and a dark text — because they layer into dismissible banners, inline validation, and icon+text combinations without requiring color to be the only signal.
Info communicates neutral information: tips, documentation links, progress updates with no urgency. Blues work well because they share color associations with interactivity, which fits — info states often contain links or actions. Use a distinct enough blue that info states do not read as interactive elements by themselves.
Accessible Feedback Implementation
<!-- Accessible error state: color + icon + text (three channels) -->
<div class="alert" role="alert" aria-live="polite">
<svg aria-hidden="true" class="alert-icon"><!-- error icon --></svg>
<p class="alert-message">
<strong>Payment failed.</strong>
Your card was declined. Please check your card details and try again.
</p>
</div>
.alert {
display: flex;
gap: 0.75rem;
padding: 1rem;
border-radius: 0.375rem;
border-width: 1px;
border-style: solid;
background-color: var(--color-feedback-danger-surface);
border-color: var(--color-feedback-danger-border);
color: var(--color-feedback-danger-text);
}
Notice the three-channel approach: color (red surface and border), shape (error icon), and text (descriptive message). This satisfies WCAG 1.4.1 — information is not conveyed by color alone.
Token Architecture: Global → Alias → Component
Enterprise-scale design systems add a third layer between primitive and semantic tokens: component tokens. This three-tier architecture is often called global → alias → component.
Tier 1: Global Tokens (Primitive)
Raw values. Numbers, colors, type sizes. No opinions. These are the atoms:
/* Global / Primitive */
--global-color-red-500: #EF4444;
--global-color-red-700: #B91C1C;
--global-space-4: 1rem;
--global-radius-md: 0.375rem;
Tier 2: Alias Tokens (Semantic)
Purpose assignments. These reference global tokens and give them roles. This is where semantic naming lives:
/* Alias / Semantic */
--alias-color-feedback-error-surface: var(--global-color-red-50);
--alias-color-feedback-error-border: var(--global-color-red-500);
--alias-color-feedback-error-text: var(--global-color-red-700);
Tier 3: Component Tokens
Component-specific assignments that reference alias tokens. They exist to allow a single component to be customized without affecting the entire semantic layer:
/* Component-level tokens */
--input-border-color-error: var(--alias-color-feedback-error-border);
--input-text-color-error: var(--alias-color-feedback-error-text);
--alert-surface-color-error: var(--alias-color-feedback-error-surface);
A component's stylesheet uses only its own component tokens:
.input--error {
border-color: var(--input-border-color-error);
}
.input--error-message {
color: var(--input-text-color-error);
}
This means if you want to customize the error border for inputs specifically — perhaps making it slightly darker for better visibility on a particular form layout — you change --input-border-color-error in the component's token file without touching the alias layer at all.
Implementation in CSS Custom Properties and Tailwind
CSS Custom Properties
The full CSS implementation uses a cascade that makes dark mode effortless:
:root {
/* Light mode defaults */
--color-surface-default: #FFFFFF;
--color-text-default: #0F172A;
--color-brand-primary: #2563EB;
--color-feedback-danger-surface: #FFF1F2;
--color-feedback-danger-border: #EF4444;
--color-feedback-danger-text: #B91C1C;
}
@media (prefers-color-scheme: dark) {
:root {
/* Dark mode overrides — same token names, different values */
--color-surface-default: #0F172A;
--color-text-default: #F8FAFC;
--color-brand-primary: #60A5FA;
--color-feedback-danger-surface: #450A0A;
--color-feedback-danger-border: #F87171;
--color-feedback-danger-text: #FCA5A5;
}
}
Every component continues referencing the same token names. Dark mode is entirely handled in the :root declaration — no conditional logic in component code.
Tailwind CSS Integration
Tailwind v4's CSS-first configuration makes semantic color integration straightforward. Define your semantic tokens in your input stylesheet and reference them throughout your Tailwind utilities:
/* styles.css — Tailwind v4 */
@import "tailwindcss";
@theme {
--color-brand-primary: #2563EB;
--color-brand-primary-hover: #1D4ED8;
--color-brand-primary-subtle: #EFF6FF;
--color-text-default: #0F172A;
--color-text-muted: #64748B;
--color-text-danger: #B91C1C;
--color-surface-default: #FFFFFF;
--color-surface-subtle: #F8FAFC;
--color-feedback-danger-surface: #FFF1F2;
--color-feedback-danger-border: #EF4444;
}
In Tailwind v3, extend your config:
// tailwind.config.js
module.exports = {
theme: {
extend: {
colors: {
brand: {
primary: 'var(--color-brand-primary)',
'primary-hover': 'var(--color-brand-primary-hover)',
subtle: 'var(--color-brand-primary-subtle)',
},
feedback: {
'danger-surface': 'var(--color-feedback-danger-surface)',
'danger-border': 'var(--color-feedback-danger-border)',
'danger-text': 'var(--color-feedback-danger-text)',
},
},
},
},
}
Now Tailwind generates utilities like bg-brand-primary, text-feedback-danger-text, and border-feedback-danger-border. Your template markup never references a raw hex value:
<div class="rounded-md border border-feedback-danger-border bg-feedback-danger-surface p-4">
<p class="text-sm text-feedback-danger-text font-medium">
This field is required.
</p>
</div>
Design Token JSON for Multi-Platform Systems
If your team works across web, iOS, and Android, token data is often stored in a platform-agnostic JSON format and transformed into platform-specific outputs (CSS custom properties, Swift constants, Kotlin constants) by a tool like Style Dictionary:
{
"color": {
"feedback": {
"danger": {
"surface": {
"$value": "#FFF1F2",
"$type": "color",
"$description": "Background for danger/error states"
},
"border": {
"$value": "#EF4444",
"$type": "color",
"$description": "Border color for danger/error states"
},
"text": {
"$value": "#B91C1C",
"$type": "color",
"$description": "Text color inside danger/error states. Meets 4.5:1 on white."
}
}
}
}
}
Style Dictionary reads this JSON and generates CSS, Swift, Kotlin, and any other format your build pipeline requires. Teams using Figma can use the Tokens Studio plugin to sync these JSON tokens directly with design files, keeping design and code in lockstep.
Common Pitfalls to Avoid
Mixing naming layers in components. If a component references both --color-blue-600 (primitive) and --color-brand-primary (semantic), the discipline breaks down. Enforce a lint rule or code review convention: component code may only reference semantic or component tokens.
Too many semantic roles. Some teams create a semantic token for every context — --color-sidebar-background, --color-modal-background, --color-drawer-background — when all three map to the same surface. Consolidate where colors genuinely share purpose. A useful test: if two semantic tokens always have the same value and always change together, merge them.
Skipping the primitive layer. Without a disciplined primitive palette, semantic tokens reference raw hex values directly. When you want to adjust your green palette, you must search through all semantic tokens that reference any green hex value. The primitive layer is what makes that change a single edit.
Naming for today's design, not tomorrow's. If --color-brand-primary is today's blue, a future rebrand to purple still works — the semantic name remains valid. But if you named it --color-brand-blue, the name is wrong the moment the brand changes. Keep semantic names free of hue references whenever possible.
Summary
Semantic color systems are a one-time investment that pays dividends every time your product changes. The key principles:
- Name colors by purpose, not appearance.
--color-text-dangerinstead of--color-red. - Separate primitive tokens (your full palette) from semantic tokens (purpose assignments).
- Reference only semantic tokens in component code. Never reach back to primitives.
- Map dark mode and theming at the semantic layer — components remain unchanged.
- For large teams, add a component token layer for per-component customization without breaking the semantic layer.
A well-named color system makes your next brand refresh, dark mode implementation, or white-label variant a configuration change rather than a codebase migration.