Theming with Styles
Stay organized with collections
Save and categorize content based on your preferences.
There are several ways you can build out your apps using Styles. What you choose
depends on where your app sits in relation to its adoption of Material Design:
Fully custom design system, not using Material Design
Recommendation: Define component styles that consume values from the
theme, and expose style parameters on design system components.
Using Material Design
Recommendation: Await Material adoption to integrate with Styles.
Use styles on your own components where possible.
The Style layer
In the traditional Compose model, customization often relies heavily on
overriding global tokens (colors and typography) provided by MaterialTheme, or
wrapping and overriding properties of a design system composable where possible.
Sometimes, there are properties within the Material layer that are not exposed
through the subsystems or parameters, but are hardcoded defaults on the
component itself.
With the Styles API, there's a new layer of abstraction that's a bridge between
subsystems and components: Styles.
Layer
Responsibility
Example
Subsystem values
Named values
val Primary = Color(0xFF34A85E)
Atomic Styles
Style that does exactly one property change
val largeSizeAtomic = Style { size(100.dp, 40.dp) }
Component Styles
Component-specific configurations
A Button with Primary background and 16dp padding. val buttonStyle = Style { contentPadding(16.dp) shape(RoundedCornerShape(8.dp)) background(Color.Blue) }
Components
The functional UI element that consumes a Style.
Button(style = buttonStyle) { ... }
Figure 1. An example of a component and how it accesses styles from a theme.
Atomic versus monolithic Styles
With the Styles API, you can break down a Style into separate atomic styles.
Instead of defining complex, component-specific styles like baseButtonStyle,
you can also create small, single-purpose utility styles. These act as your
"atoms".
One of the powerful features of the new Styles API is the then operator, which
lets you merge multiple Style objects. This lets you build a component using
atomic utility classes.
Traditional (non-atomic):
// One large monolithic stylevalbuttonStyle=Style{contentPadding(16.dp)shape(RoundedCornerShape(8.dp))background(Color.Blue)}
// Combine atoms to create the final appearancevalbuttonStyle=paddingAtomicthenroundedCornerShapeAtomicthenprimaryBackgroundAtomictheninteractiveShadowAtomic
Consider the following options when adopting Styles within your design system,
depending on where in the spectrum your design system lies.
Custom design system with Styles
Consider when: You've been handed an extensive brand guide that is not
based on Material Design, and you are not planning to use Material Design.
Strategy: Implement a fully custom design system, and expose styles as part
of the theme.
This option is the custom path if you don't use Material as your main design
system language. You bypass MaterialTheme entirely for visual definitions and
have created your own custom theme already. You build a CompanyTheme that
acts as a container for your Styles.
How it works: Create a CompanyTheme object that holds Style objects
for every component in your system. Your components (either wrappers around
Material logic or custom Box or Layout implementations) consume these
styles directly, and expose a Style parameter for consumers of your design
system.
The Style layer: Styles are the primary definition of your design
system. Tokens are named variables fed into these styles. This allows for
deep customization, such as defining unique animations for state changes
(for example, animating scale and color on press).
If you are building out your own custom theme without using Material, and
want to adopt styles, add your list of styles to your Theme. This lets you
access your base styles from anywhere in your project.
Create a Styles class that stores the various styles in your application
and create the defaults. For example, in the Jetsnack app - the class is
named JetsnackStyles:
@ComposablefunCustomButton(modifier:Modifier,style:Style=Style,text:String){valinteractionSource=remember{MutableInteractionSource()}valstyleState=remember(interactionSource){MutableStyleState(interactionSource)}// Apply style to top level container in combination with incoming style from parameter.Box(modifier=modifier.clickable(interactionSource=interactionSource,indication=null,enabled=true,role=Role.Button,onClick={},).styleable(styleState,JetsnackTheme.styles.buttonStyle,style)){Text(text)}}
Beyond global theme adoption, there are alternative strategies for incorporating
Styles into your apps. You can leverage Styles inline for specific call
sites or use static definitions when full theming capabilities are unnecessary.
Styles shouldn't be swapped conditionally unless the whole style is
fundamentally different. You should prefer accessing dynamic tokens inside a
visual definition rather than switching between distinct style objects.
Content and code samples on this page are subject to the licenses described in the Content License. Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.
Last updated 2026-08-14 UTC.
[[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Missing the information I need","missingTheInformationINeed","thumb-down"],["Too complicated / too many steps","tooComplicatedTooManySteps","thumb-down"],["Out of date","outOfDate","thumb-down"],["Samples / code issue","samplesCodeIssue","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2026-08-14 UTC."],[],[]]