Theming
Theming lets you customize your app’s look by adjusting colors, fonts, and styles to match your brand or preferences.
Overview
<p class="mb-3">Phoenix Tailwind uses <a href="https://hbui.dev/" target="_blank">Hummingbird,</a> a modern component system built on <a href="https://tailwindcss.com/" target="_blank">Tailwind CSS v4,</a> designed to make theming clean, scalable, and extremely flexible.
Phoenix Tailwind provides a set of theme variables (design tokens) that control the visual foundation of the UI - including colors, typography, shadows, and more.</p>
<ul class="space-y-2">
<li>Theme variables such as <code>--color-primary </code>or <code>--shadow-md </code>are integrated directly into Tailwind utilities. That means you can style components using familiar classes like: <code>bg-primary, text-primary, shadow-md</code> etc., and they will automatically use the values defined in your theme.</li>
<li>To override the default theme globally, simply redefine variables inside the <code>@theme { ... } </code>block in <code>src/css/theme.css</code> after importing Hummingbird UI styles.</li>
<li>Multiple themes (e.g., light, dark, or custom variants) can be created by overriding the same variables within a scoped theme selector such as <code>@variant dark { ... } </code>or <code>[data-theme="dark"] { ... }.</code></li>
<li>A Reboot layer is provided in <code>src/css/reboot.css</code>, a base CSS reset layer that applies consistent element styling across browsers, ensuring a clean and uniform design baseline.</li>
</ul>
Phoenix Tailwind uses Hummingbird, a modern component system built on Tailwind CSS v4, designed to make theming clean, scalable, and extremely flexible. Phoenix Tailwind provides a set of theme variables (design tokens) that control the visual foundation of the UI - including colors, typography, shadows, and more.
- Theme variables such as
--color-primaryor--shadow-mdare integrated directly into Tailwind utilities. That means you can style components using familiar classes like:bg-primary, text-primary, shadow-mdetc., and they will automatically use the values defined in your theme. - To override the default theme globally, simply redefine variables inside the
@theme { ... }block insrc/css/theme.cssafter importing Hummingbird UI styles. - Multiple themes (e.g., light, dark, or custom variants) can be created by overriding the same variables within a scoped theme selector such as
@variant dark { ... }or[data-theme="dark"] { ... }. - A Reboot layer is provided in
src/css/reboot.css, a base CSS reset layer that applies consistent element styling across browsers, ensuring a clean and uniform design baseline.
Theme variables
<p class="mb-3">Phoenix Tailwind provides a comprehensive set of theme variables covering all aspects of the interface. Updating these variables allows the appearance to be easily customized for different design requirements.</p><pre class="language-css"><code class="lang-css">@theme {
--color-gray-50: var(--gray-50);
--color-gray-100: var(--gray-100);
--color-gray-200: var(--gray-200);
--color-gray-300: var(--gray-300);
--color-gray-400: var(--gray-400);
--color-gray-500: var(--gray-500);
--color-gray-600: var(--gray-600);
--color-gray-700: var(--gray-700);
--color-gray-800: var(--gray-800);
--color-gray-900: var(--gray-900);
--color-gray-1000: var(--gray-1000);
--color-gray-1100: var(--gray-1100);
--color-blue-50: #f5f8ff;
--color-blue-100: #e5edff;
--color-blue-200: #adc5ff;
--color-blue-300: #85a9ff;
--color-blue-400: #6090ff;
--color-blue-500: #3874ff;
--color-blue-600: #004dff;
--color-blue-700: #003cc7;
--color-blue-800: #0033aa;
--color-blue-900: #00267b;
--color-blue-1000: #00174d;
--color-red-50: #ffedeb;
--color-red-100: #ffe0db;
--color-red-200: #fabcb3;
--color-red-300: #f48270;
--color-red-400: #fb624a;
--color-red-500: #fa3b1d;
--color-red-600: #cc1b00;
--color-red-700: #b81800;
--color-red-800: #901400;
--color-red-900: #630d00;
--color-red-1000: #380700;
--color-green-50: #f0fdec;
--color-green-100: #d9fbd0;
--color-green-200: #bee8b4;
--color-green-300: #90d67f;
--color-green-400: #51c035;
--color-green-500: #25b003;
--color-green-600: #23890b;
--color-green-700: #1c6c09;
--color-green-800: #115a00;
--color-green-900: #0b3d00;
--color-green-1000: #061f00;
--color-orange-50: #fff6e0;
--color-orange-100: #ffefca;
--color-orange-200: #ffe6ad;
--color-orange-300: #ffcc85;
--color-orange-400: #ea9c3c;
--color-orange-500: #e5780b;
--color-orange-600: #d6630a;
--color-orange-700: #bc3803;
--color-orange-800: #901400;
--color-orange-900: #630d00;
--color-orange-1000: #380700;
--color-cyan-50: #f0faff;
--color-cyan-100: #c7ebff;
--color-cyan-200: #96d9ff;
--color-cyan-300: #60c6ff;
--color-cyan-400: #33acef;
--color-cyan-500: #0097eb;
--color-cyan-600: #0080c7;
--color-cyan-700: #005585;
--color-cyan-800: #004870;
--color-cyan-900: #003a5b;
--color-cyan-1000: #002337;
/* Body colors */
--text-color-body: var(--color-gray-900);
--background-color-body: var(--color-gray-50);
--text-color-body-secondary: var(--color-gray-800);
--background-color-body-secondary: var(--color-gray-200);
--text-color-body-tertiary: var(--color-gray-700);
--background-color-body-tertiary: var(--color-gray-300);
--text-color-body-quaternary: var(--color-gray-500);
--background-color-body-quaternary: var(--color-gray-400);
--text-color-body-emphasis: var(--color-gray-1100);
--background-color-body-emphasis: var(--color-white);
--text-color-body-highlight: var(--color-gray-1000);
--background-color-body-highlight: var(--color-gray-100);
/* Emphasis text colors */
--text-color-primary-emphasis: var(--color-blue-700);
--text-color-secondary-emphasis: var(--color-gray-700);
--text-color-success-emphasis: var(--color-green-700);
--text-color-info-emphasis: var(--color-cyan-700);
--text-color-warning-emphasis: var(--color-orange-700);
--text-color-danger-emphasis: var(--color-red-700);
--text-color-light-emphasis: var(--color-gray-1100);
--text-color-dark-emphasis: var(--color-white);
/* Subtle text colors */
--text-color-primary-subtle: var(--color-blue-100);
--text-color-secondary-subtle: var(--color-gray-100);
--text-color-success-subtle: var(--color-green-100);
--text-color-info-subtle: var(--color-cyan-100);
--text-color-warning-subtle: var(--color-orange-100);
--text-color-danger-subtle: var(--color-red-100);
/* subtle background colors */
--background-color-primary-subtle: var(--color-blue-100);
--background-color-secondary-subtle: var(--color-gray-100);
--background-color-success-subtle: var(--color-green-100);
--background-color-info-subtle: var(--color-cyan-100);
--background-color-warning-subtle: var(--color-orange-100);
--background-color-danger-subtle: var(--color-red-100);
--background-color-light-subtle: color-mix(in oklab, var(--gray-100), var(--color-white));
--background-color-dark-subtle: var(--gray-400);
/* primary */
--color-primary-lighter: var(--color-blue-200);
--color-primary-light: var(--color-blue-300);
--color-primary: var(--color-blue-500);
--color-primary-dark: var(--color-blue-600);
--color-primary-darker: var(--color-blue-700);
/* secondary */
--color-secondary-lighter: var(--color-gray-200);
--color-secondary-light: var(--color-gray-300);
--color-secondary: var(--color-gray-900);
--color-secondary-dark: var(--color-gray-1000);
--color-secondary-darker: var(--color-gray-700);
/* danger */
--color-danger-lighter: var(--color-red-200);
--color-danger-light: var(--color-red-300);
--color-danger: var(--color-red-500);
--color-danger-dark: var(--color-red-600);
--color-danger-darker: var(--color-red-700);
/* warning */
--color-warning-lighter: var(--color-orange-200);
--color-warning-light: var(--color-orange-300);
--color-warning: var(--color-orange-500);
--color-warning-dark: var(--color-orange-600);
--color-warning-darker: var(--color-orange-700);
/* success */
--color-success-lighter: var(--color-green-200);
--color-success-light: var(--color-green-300);
--color-success: var(--color-green-500);
--color-success-dark: var(--color-green-600);
--color-success-darker: var(--color-green-700);
/* info */
--color-info-lighter: var(--color-cyan-200);
--color-info-light: var(--color-cyan-300);
--color-info: var(--color-cyan-500);
--color-info-dark: var(--color-cyan-600);
--color-info-darker: var(--color-cyan-700);
--color-light: var(--gray-100);
--color-dark: var(--gray-1100);
/* Border colors */
--border-color-base: var(--color-gray-300);
--border-color-translucent: --alpha(var(--border-color-base) / 54%);
--border-color-primary-subtle: var(--color-blue-300);
--border-color-secondary-subtle: var(--gray-300);
--border-color-success-subtle: var(--color-green-300);
--border-color-info-subtle: var(--color-cyan-300);
--border-color-warning-subtle: var(--color-orange-300);
--border-color-danger-subtle: var(--color-red-300);
--border-color-light-subtle: var(--gray-100);
--border-color-dark-subtle: var(--gray-500);
/* Line height */
--leading-base: 1.49;
--leading-sm: 1.2;
--leading-lg: 1.4;
/* Font size */
--text-xs: 8.192px;
--text-xs--line-height: inherit;
--text-sm: 10.24px;
--text-sm--line-height: inherit;
--text-md: 12.8px;
--text-md--line-height: inherit;
--text-base: 16px;
--text-base--line-height: inherit;
--text-lg: 20px;
--text-lg--line-height: inherit;
--text-xl: 25px;
--text-xl--line-height: inherit;
--text-2xl: 31.25px;
--text-2xl--line-height: inherit;
--text-3xl: 39.063px;
--text-3xl--line-height: inherit;
--text-4xl: 48.828px;
--text-4xl--line-height: inherit;
--text-5xl: 61.035px;
--text-5xl--line-height: inherit;
--text-6xl: 76.294px;
--text-6xl--line-height: inherit;
/* Shadows */
--shadow-base: 0 0.5rem 1rem --alpha(var(--color-black) / 15%);
--shadow-sm: 0 0.125rem 0.25rem --alpha(var(--color-black) / 7.5%);
--shadow-lg: 0 1rem 3rem --alpha(var(--color-black) / 17.5%);
--shadow-inset: inset 0 1px 2px --alpha(var(--color-black) / 7.5%);
/* Font family */
--font-sans: 'Nunito Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
/* Breakpoints */
--breakpoint-sm: 576px;
--breakpoint-md: 768px;
--breakpoint-lg: 992px;
--breakpoint-xl: 1200px;
--breakpoint-2xl: 1540px;
}</code></pre>
Phoenix Tailwind provides a comprehensive set of theme variables covering all aspects of the interface. Updating these variables allows the appearance to be easily customized for different design requirements.
@theme {
--color-gray-50: var(--gray-50);
--color-gray-100: var(--gray-100);
--color-gray-200: var(--gray-200);
--color-gray-300: var(--gray-300);
--color-gray-400: var(--gray-400);
--color-gray-500: var(--gray-500);
--color-gray-600: var(--gray-600);
--color-gray-700: var(--gray-700);
--color-gray-800: var(--gray-800);
--color-gray-900: var(--gray-900);
--color-gray-1000: var(--gray-1000);
--color-gray-1100: var(--gray-1100);
--color-blue-50: #f5f8ff;
--color-blue-100: #e5edff;
--color-blue-200: #adc5ff;
--color-blue-300: #85a9ff;
--color-blue-400: #6090ff;
--color-blue-500: #3874ff;
--color-blue-600: #004dff;
--color-blue-700: #003cc7;
--color-blue-800: #0033aa;
--color-blue-900: #00267b;
--color-blue-1000: #00174d;
--color-red-50: #ffedeb;
--color-red-100: #ffe0db;
--color-red-200: #fabcb3;
--color-red-300: #f48270;
--color-red-400: #fb624a;
--color-red-500: #fa3b1d;
--color-red-600: #cc1b00;
--color-red-700: #b81800;
--color-red-800: #901400;
--color-red-900: #630d00;
--color-red-1000: #380700;
--color-green-50: #f0fdec;
--color-green-100: #d9fbd0;
--color-green-200: #bee8b4;
--color-green-300: #90d67f;
--color-green-400: #51c035;
--color-green-500: #25b003;
--color-green-600: #23890b;
--color-green-700: #1c6c09;
--color-green-800: #115a00;
--color-green-900: #0b3d00;
--color-green-1000: #061f00;
--color-orange-50: #fff6e0;
--color-orange-100: #ffefca;
--color-orange-200: #ffe6ad;
--color-orange-300: #ffcc85;
--color-orange-400: #ea9c3c;
--color-orange-500: #e5780b;
--color-orange-600: #d6630a;
--color-orange-700: #bc3803;
--color-orange-800: #901400;
--color-orange-900: #630d00;
--color-orange-1000: #380700;
--color-cyan-50: #f0faff;
--color-cyan-100: #c7ebff;
--color-cyan-200: #96d9ff;
--color-cyan-300: #60c6ff;
--color-cyan-400: #33acef;
--color-cyan-500: #0097eb;
--color-cyan-600: #0080c7;
--color-cyan-700: #005585;
--color-cyan-800: #004870;
--color-cyan-900: #003a5b;
--color-cyan-1000: #002337;
/* Body colors */
--text-color-body: var(--color-gray-900);
--background-color-body: var(--color-gray-50);
--text-color-body-secondary: var(--color-gray-800);
--background-color-body-secondary: var(--color-gray-200);
--text-color-body-tertiary: var(--color-gray-700);
--background-color-body-tertiary: var(--color-gray-300);
--text-color-body-quaternary: var(--color-gray-500);
--background-color-body-quaternary: var(--color-gray-400);
--text-color-body-emphasis: var(--color-gray-1100);
--background-color-body-emphasis: var(--color-white);
--text-color-body-highlight: var(--color-gray-1000);
--background-color-body-highlight: var(--color-gray-100);
/* Emphasis text colors */
--text-color-primary-emphasis: var(--color-blue-700);
--text-color-secondary-emphasis: var(--color-gray-700);
--text-color-success-emphasis: var(--color-green-700);
--text-color-info-emphasis: var(--color-cyan-700);
--text-color-warning-emphasis: var(--color-orange-700);
--text-color-danger-emphasis: var(--color-red-700);
--text-color-light-emphasis: var(--color-gray-1100);
--text-color-dark-emphasis: var(--color-white);
/* Subtle text colors */
--text-color-primary-subtle: var(--color-blue-100);
--text-color-secondary-subtle: var(--color-gray-100);
--text-color-success-subtle: var(--color-green-100);
--text-color-info-subtle: var(--color-cyan-100);
--text-color-warning-subtle: var(--color-orange-100);
--text-color-danger-subtle: var(--color-red-100);
/* subtle background colors */
--background-color-primary-subtle: var(--color-blue-100);
--background-color-secondary-subtle: var(--color-gray-100);
--background-color-success-subtle: var(--color-green-100);
--background-color-info-subtle: var(--color-cyan-100);
--background-color-warning-subtle: var(--color-orange-100);
--background-color-danger-subtle: var(--color-red-100);
--background-color-light-subtle: color-mix(in oklab, var(--gray-100), var(--color-white));
--background-color-dark-subtle: var(--gray-400);
/* primary */
--color-primary-lighter: var(--color-blue-200);
--color-primary-light: var(--color-blue-300);
--color-primary: var(--color-blue-500);
--color-primary-dark: var(--color-blue-600);
--color-primary-darker: var(--color-blue-700);
/* secondary */
--color-secondary-lighter: var(--color-gray-200);
--color-secondary-light: var(--color-gray-300);
--color-secondary: var(--color-gray-900);
--color-secondary-dark: var(--color-gray-1000);
--color-secondary-darker: var(--color-gray-700);
/* danger */
--color-danger-lighter: var(--color-red-200);
--color-danger-light: var(--color-red-300);
--color-danger: var(--color-red-500);
--color-danger-dark: var(--color-red-600);
--color-danger-darker: var(--color-red-700);
/* warning */
--color-warning-lighter: var(--color-orange-200);
--color-warning-light: var(--color-orange-300);
--color-warning: var(--color-orange-500);
--color-warning-dark: var(--color-orange-600);
--color-warning-darker: var(--color-orange-700);
/* success */
--color-success-lighter: var(--color-green-200);
--color-success-light: var(--color-green-300);
--color-success: var(--color-green-500);
--color-success-dark: var(--color-green-600);
--color-success-darker: var(--color-green-700);
/* info */
--color-info-lighter: var(--color-cyan-200);
--color-info-light: var(--color-cyan-300);
--color-info: var(--color-cyan-500);
--color-info-dark: var(--color-cyan-600);
--color-info-darker: var(--color-cyan-700);
--color-light: var(--gray-100);
--color-dark: var(--gray-1100);
/* Border colors */
--border-color-base: var(--color-gray-300);
--border-color-translucent: --alpha(var(--border-color-base) / 54%);
--border-color-primary-subtle: var(--color-blue-300);
--border-color-secondary-subtle: var(--gray-300);
--border-color-success-subtle: var(--color-green-300);
--border-color-info-subtle: var(--color-cyan-300);
--border-color-warning-subtle: var(--color-orange-300);
--border-color-danger-subtle: var(--color-red-300);
--border-color-light-subtle: var(--gray-100);
--border-color-dark-subtle: var(--gray-500);
/* Line height */
--leading-base: 1.49;
--leading-sm: 1.2;
--leading-lg: 1.4;
/* Font size */
--text-xs: 8.192px;
--text-xs--line-height: inherit;
--text-sm: 10.24px;
--text-sm--line-height: inherit;
--text-md: 12.8px;
--text-md--line-height: inherit;
--text-base: 16px;
--text-base--line-height: inherit;
--text-lg: 20px;
--text-lg--line-height: inherit;
--text-xl: 25px;
--text-xl--line-height: inherit;
--text-2xl: 31.25px;
--text-2xl--line-height: inherit;
--text-3xl: 39.063px;
--text-3xl--line-height: inherit;
--text-4xl: 48.828px;
--text-4xl--line-height: inherit;
--text-5xl: 61.035px;
--text-5xl--line-height: inherit;
--text-6xl: 76.294px;
--text-6xl--line-height: inherit;
/* Shadows */
--shadow-base: 0 0.5rem 1rem --alpha(var(--color-black) / 15%);
--shadow-sm: 0 0.125rem 0.25rem --alpha(var(--color-black) / 7.5%);
--shadow-lg: 0 1rem 3rem --alpha(var(--color-black) / 17.5%);
--shadow-inset: inset 0 1px 2px --alpha(var(--color-black) / 7.5%);
/* Font family */
--font-sans: 'Nunito Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
/* Breakpoints */
--breakpoint-sm: 576px;
--breakpoint-md: 768px;
--breakpoint-lg: 992px;
--breakpoint-xl: 1200px;
--breakpoint-2xl: 1540px;
}

