Colors
Colour roles, hue scopes, and intents
Colour comes in three layers. Ramps hold twenty steps per hue. A theme maps one hue onto the
steps for a scope. Roles read the theme as light-dark() pairs, so a component names what a
colour is for and the scheme picks the value.
import { role } from "@nyte-ai/ui/styles/vars.stylex";
import { intent, surfaceTheme } from "@nyte-ai/ui/surface-theme";Rules
- Components read a role. They never write a hex,
rgb(),oklch(), orlight-dark(). - A new colour need is a new role in
roles.stylex.tswith a handle invars.stylex.ts. - Readable text uses
contentPrimaryorcontentSecondary.contentTertiaryis for placeholders, disabled hints, and decoration. - Glyphs use
contentInteractiveTertiaryor a stronger role. - Meaning picks a hue through an intent; a category picks one through a scope. Both reuse the same role names.
- Nothing paints a page background in the desktop app; the window's material shows through.
Content
| Role | Light | Dark |
|---|---|---|
role.contentPrimary--nyte-content-primary | #2c2c2b | #e6e5e3 |
role.contentSecondary--nyte-content-secondary | #5f5e59 | #a19e99 |
role.contentTertiary--nyte-content-tertiary | #a19e99 | #5f5e59 |
role.contentDisabled--nyte-content-disabled | #d4d3cf | #383836 |
role.contentChrome--nyte-content-chrome | #5f5e59 | #ada9a3 |
role.contentInteractivePrimary--nyte-content-interactive-primary | #383836 | #f0efed |
role.contentInteractiveSecondary--nyte-content-interactive-secondary | #5f5e59 | #bcbab6 |
role.contentInteractiveTertiary--nyte-content-interactive-tertiary | #8e8b86 | #7d7a75 |
role.contentOnInteractiveStrong--nyte-content-on-interactive-strong | #ffffff | #ffffff |
role.contentOnControl--nyte-content-on-control | #ffffff | #ffffff |
Border
| Role | Light | Dark |
|---|---|---|
role.borderPrimary--nyte-border-primary | #e6e5e3 | #383836 |
role.borderSecondary--nyte-border-secondary | #f0efed | #262626 |
role.borderStrong--nyte-border-strong | #d4d3cf | #5f5e59 |
role.borderControl--nyte-border-control | #8e8b86 | #8e8b86 |
role.borderInteractivePrimary--nyte-border-interactive-primary | #8e8b86 | #8e8b86 |
role.borderPrimaryTranslucent--nyte-border-primary-translucent | #1b12001c | #fffff022 |
role.borderSecondaryTranslucent--nyte-border-secondary-translucent | #2b1c0012 | #ffffff0f |
role.borderStrongTranslucent--nyte-border-strong-translucent | #1b150030 | #fffceb4e |
role.borderControlTranslucent--nyte-border-control-translucent | #110b0079 | #fff9ef82 |
Surface
| Role | Light | Dark |
|---|---|---|
role.bgBase--nyte-bg-base | #ffffff | #1b1b1b |
role.bgChrome--nyte-bg-chrome | #fbfbfa | #191919 |
role.bgMuted--nyte-bg-muted | #f9f8f7 | #202020 |
role.bgElevated--nyte-bg-elevated | #ffffff | #202020 |
role.bgMutedTranslucent--nyte-bg-muted-translucent | #40200008 | #ffffff08 |
role.bgScrim--nyte-bg-scrim | #00000026 | #000000bf |
role.bgScrimTranslucent--nyte-bg-scrim-translucent | #1b150030 | #fffceb4e |
role.bgHover--nyte-bg-hover | #3b14000d | #ffffff0f |
role.bgPressed--nyte-bg-pressed | #3b140018 | #ffffff1a |
Interactive
| Role | Light | Dark |
|---|---|---|
role.bgInteractivePrimary--nyte-bg-interactive-primary | #e6e5e3 | #383836 |
role.bgInteractivePrimaryPressed--nyte-bg-interactive-primary-pressed | #c2c1bf | #434341 |
role.bgInteractiveSecondary--nyte-bg-interactive-secondary | #f5f3f2 | #262626 |
role.bgInteractiveSecondaryHover--nyte-bg-interactive-secondary-hover | #e5e3e2 | #292929 |
role.bgInteractiveSecondaryPressed--nyte-bg-interactive-secondary-pressed | #cfcdcc | #2e2e2e |
role.bgInteractiveStrong--nyte-bg-interactive-strong | #2c2c2b | #5f5e59 |
role.bgInteractivePrimaryTranslucent--nyte-bg-interactive-primary-translucent | #1b12001c | #fffff022 |
role.bgInteractiveSecondaryTranslucent--nyte-bg-interactive-secondary-translucent | #3b14000d | #ffffff0f |
role.buttonFill--nyte-button-fill | #6b6864 | #6b6864 |
role.buttonFillHover--nyte-button-fill-hover | #64615c | #64615c |
role.buttonFillPressed--nyte-button-fill-pressed | #5a5752 | #5a5752 |
Control
| Role | Light | Dark |
|---|---|---|
role.bgControl--nyte-bg-control | #8e8b86 | #5f5e59 |
role.bgControlHover--nyte-bg-control-hover | #84817d | #666560 |
role.bgControlPressed--nyte-bg-control-pressed | #777470 | #6f6e69 |
role.bgControlSelected--nyte-bg-control-selected | #2c2c2b | #5f5e59 |
role.bgControlSelectedHover--nyte-bg-control-selected-hover | #282827 | #666560 |
role.bgControlSelectedPressed--nyte-bg-control-selected-pressed | #232322 | #6f6e69 |
Hue scopes
Pass a scope to props() and every role inside reads that hue. custom takes its hue from
--nyte-custom-hue.
grayLabelActionbrownLabelActionorangeLabelActionyellowLabelActiongreenLabelActionblueLabelActionpurpleLabelActionpinkLabelActionredLabelActiontealLabelActioncustomLabelAction<span {...props(surfaceTheme.green, styles.badge)}>Added</span>Intents
| Intent | Hue | Text | Use |
|---|---|---|---|
intent.primary | blue | #3c5f85 | Filled actions, links, the current item |
intent.success | green | #116d3e | Status text: done, passing |
intent.warning | yellow | #955a14 | Status text: needs attention |
intent.danger | red | #a63536 | Status text, destructive menu items and alert actions |
The focus ring ignores scopes. It reads appearance.focusRing, a fixed blue.