Palette theming¶
Palette exposes theme tokens in two layers:
- Core semantic tokens: colors, spacing, shapes, typography, opacity, motion, elevation, and shared control density.
- Component tokens:
PaletteComponentThemes, available fromPaletteTheme.componentThemes.
Component defaults should follow this precedence:
- Explicit component parameter.
- Explicit parameter passed to an
XxxDefaults.colors()or similar builder. PaletteTheme.componentThemes.xxx.- Core semantic tokens such as
PaletteTheme.colors,PaletteTheme.spacing, andPaletteTheme.typography. - A controlled fallback value for algorithmic or compatibility constants.
Core tokens¶
PaletteColors keeps the existing fields (primary, surface, onSurface, border, error, success, warning) and adds semantic state fields:
- Text:
textPrimary,textSecondary,textTertiary,textDisabled,inverseOnSurface. - Surface:
pageBackground,appBackground,surfaceElevated,surfaceOverlay,inverseSurface. - State:
borderHover,borderFocus,borderDisabled,bgDisabled,bgHover,bgPressed,bgSelected. - Structure:
divider,overlay,shadow,shadowFocus,shadowError,info,danger.
Use copy() when you want to preserve all existing derived values. Use derive() when you want derived semantic values to be recomputed from a changed core value:
val brandColors = PaletteColors.light().derive(
primary = Color(0xFF0057D9),
surface = Color(0xFFFFFFFF),
)
PaletteOpacity, PaletteMotion, PaletteElevation, and PaletteControlTokens centralize repeated disabled, selected, animation, elevation, border, and control-size decisions. Form-like components should read PaletteControlTokens through their XxxDefaults compatibility functions instead of reading ComponentSize constants directly.
Component themes¶
PaletteComponentThemes is the root-level component override entry:
val colors = PaletteColors.light().derive(primary = Color(0xFF0057D9))
val baseComponents = PaletteComponentThemes.default(colors = colors)
PaletteMaterialTheme(
colors = colors,
componentThemes = baseComponents.copy(
button = baseComponents.button.copy(
primaryContainerColor = Color(0xFF0057D9),
disabledAlpha = 0.56f,
),
card = baseComponents.card.copy(
cornerRadius = 0.dp,
elevation = 0.dp,
),
),
) {
App()
}
The current component theme registry includes:
| Token | Components using it |
|---|---|
borderContainer |
BorderContainer, BorderContainerDefaults |
button |
PButton, ButtonDefaults |
checkbox |
ColoredCheckBox, CheckboxDefaults |
radio |
PRadio, PRadioGroup, RadioDefaults |
switch |
PSwitch, SwitchDefaults |
selectionControl |
PSlider, PRate, PToggle, PToggleGroup, PSegmented, related Defaults |
form |
PForm, PFormItem, FormDefaults |
textField |
BorderTextField, TextArea, PasswordField, TextFieldDefaults |
select |
PSelect, PAutocomplete, PCascader, PCascaderPanel, PTreeSelect, PMentions, related Defaults |
dateTime |
PDatePicker, PTimePicker, PDateTimeRange, PCalendar, related Defaults |
input |
PInputNumber, PInputOTP, PSearchBar, related Defaults |
card |
PCard, CardDefaults |
table |
PTable, TableDefaults |
dataGrid |
PDataGrid, DataGridDefaults |
dataDisplay |
PList, PDescriptions, PBadge, PAvatar, PPagination, related Defaults |
dataEntry |
PTimeline, PTransfer, PTree, PSortable, PVirtualList, PInfiniteScroll, PUpload, related Defaults |
navigationMenu |
PMenu, PContextMenu, PCommandPalette, PTabs, PBreadcrumb, PSteps, PCollapse, related Defaults |
appBar |
Toolbar, PPageHeader, related Defaults |
floatingLayer |
PTooltip, PPopover, PPopconfirm, PTour, related Defaults |
dialog |
PDialog, DialogDefaults |
drawer |
PDrawer, DrawerDefaults |
popup |
PPopup, PopupDefaults |
actionSheet |
PActionSheet, ActionSheetDefaults |
message |
PMessage, MessageDefaults |
notification |
PNotification, NotificationDefaults |
toast |
PToast, ToastDefaults |
tag |
PTag, PEditableTagGroup, TagDefaults |
feedbackDisplay |
PAlert, PResult, PEmpty, PStatistic, related Defaults |
progress |
PProgress, PCircleProgress, PDashboardProgress, PLoading, PSkeleton*, related Defaults |
media |
PCarousel, PImage, PColorPicker, related Defaults |
utility |
PQRCode, PBarcode, PWatermark, related Defaults |
layout |
PSpace, PRow, PAffix, related Defaults |
floatingAction |
PBacktop, PFloatButton, related Defaults |
screen |
Screen, ScreenDefaults |
Additional components should be migrated by adding a small immutable PaletteXxxTokens class or extending the closest domain token group, then routing XxxDefaults through PaletteTheme.componentThemes.xxx. Keep existing public constants as compatibility aliases unless a major version intentionally removes them.
Common overrides¶
Brand theme:
val colors = PaletteColors.light().derive(
primary = Color(0xFF006ADC),
bgSelected = Color(0x1A006ADC),
borderFocus = Color(0x99006ADC),
)
PaletteTheme(colors = colors) {
App()
}
Compact density:
val control = PaletteControlTokens.default().copy(
medium = PaletteControlSizeTokens(
height = 32.dp,
fontSize = 14.sp,
iconSize = 18.dp,
horizontalPadding = 12.dp,
verticalPadding = 4.dp,
cornerRadius = 4.dp,
),
)
PaletteTheme(control = control) {
App()
}
Sharp surfaces:
val components = PaletteComponentThemes.default().let { base ->
base.copy(
card = base.card.copy(cornerRadius = 0.dp),
dialog = base.dialog.copy(borderRadius = 0.dp),
tag = base.tag.copy(
small = base.tag.small.copy(cornerRadius = 2.dp),
medium = base.tag.medium.copy(cornerRadius = 2.dp),
large = base.tag.large.copy(cornerRadius = 2.dp),
),
)
}
PaletteTheme(componentThemes = components) {
App()
}
Dark mode:
val colors = PaletteColors.dark().derive(
primary = Color(0xFF7AB7FF),
surfaceElevated = Color(0xFF252525),
)
PaletteMaterialTheme(colors = colors, darkTheme = true) {
App()
}
Component author checklist¶
When adding or migrating a component:
- Define the major user-facing style surface: colors, size, typography, radius, border, elevation, motion, and opacity.
- Add immutable token data only for those major surfaces.
- Derive default tokens from core tokens in
PaletteComponentThemes.default(). - Route
XxxDefaultsthroughPaletteTheme.componentThemes.xxx. - Keep public constants as compatibility aliases and add composable token-backed functions beside them.
- Add tests for root theme override and explicit parameter precedence.
- Leave algorithmic constants explicit when they are not a style decision, and document the reason in code if it is not obvious.
Static audit¶
ThemeTokenizationStaticAuditTest guards the current migration boundary for Defaults files:
- Component Defaults should not read
PaletteTheme.colorsdirectly; route major visual style throughPaletteTheme.componentThemes. TextDefaultsis allowlisted because it intentionally exposes base text semantic roles.- Defaults should not introduce raw
Color.Black/Color.Whiteor inline alpha state colors without a narrow documented allowlist.