Creating Custom Themes and Typography in Jetpack Compose

Learn how to create custom themes and typography in Jetpack Compose, a modern UI framework for Android development.

Jetpack Compose, Android’s modern toolkit for building native UIs, has revolutionized the way developers create user interfaces. With its declarative approach, Compose simplifies UI development, making it more intuitive and efficient. One of the key aspects of building a cohesive and visually appealing app is theming and typography. In this article, we’ll dive deep into creating custom themes and typography in Jetpack Compose, exploring how to tailor these elements to fit your app’s unique design language.


Why Theming and Typography Matter

Before we dive into the technical details, let’s briefly discuss why theming and typography are so important in app development.

  1. Consistency: A well-defined theme ensures that your app has a consistent look and feel across all screens. This consistency enhances the user experience by making the app feel cohesive and professional.
  2. Brand Identity: Custom themes and typography allow you to align your app’s design with your brand’s identity. This includes using specific colors, fonts, and styles that reflect your brand’s personality.
  3. Accessibility: Proper theming and typography can improve accessibility by ensuring sufficient contrast, readable fonts, and scalable text sizes.
  4. Maintainability: By centralizing your design system in a theme, you can easily make global changes to your app’s appearance without modifying individual components.

With these benefits in mind, let’s explore how to create custom themes and typography in Jetpack Compose.


Understanding Jetpack Compose Theming

Jetpack Compose provides a powerful theming system that allows you to define and apply themes across your app. At the core of this system is the MaterialTheme component, which is based on Google’s Material Design guidelines. However, you can customize this theme to suit your app’s needs.

Key Components of a Theme

  1. Colors: Define the color palette for your app, including primary, secondary, background, and surface colors.
  2. Typography: Define the text styles used throughout your app, such as headings, body text, and captions.
  3. Shapes: Define the shapes of components like buttons, cards, and dialogs.
  4. Elevation: Define the shadow and elevation levels for components.

In this post, we’ll focus on colors and typography, as these are the most commonly customized aspects of a theme.


Creating a Custom Theme

To create a custom theme in Jetpack Compose, you’ll need to define your own color palette and typography. Let’s start by defining a custom color palette.

Step 1: Define Your Color Palette

In Jetpack Compose, colors are typically defined using the Color class. You can create a custom color palette by defining a set of colors and organizing them into a data class.

import androidx.compose.ui.graphics.Color

data class CustomColors(
    val primary: Color,
    val secondary: Color,
    val background: Color,
    val surface: Color,
    val onPrimary: Color,
    val onSecondary: Color,
    val onBackground: Color,
    val onSurface: Color
)

val LightCustomColors = CustomColors(
    primary = Color(0xFF6200EE),
    secondary = Color(0xFF03DAC6),
    background = Color(0xFFFFFFFF),
    surface = Color(0xFFFFFFFF),
    onPrimary = Color(0xFFFFFFFF),
    onSecondary = Color(0xFF000000),
    onBackground = Color(0xFF000000),
    onSurface = Color(0xFF000000)
)

val DarkCustomColors = CustomColors(
    primary = Color(0xFFBB86FC),
    secondary = Color(0xFF03DAC6),
    background = Color(0xFF121212),
    surface = Color(0xFF1E1E1E),
    onPrimary = Color(0xFF000000),
    onSecondary = Color(0xFF000000),
    onBackground = Color(0xFFFFFFFF),
    onSurface = Color(0xFFFFFFFF)
)

Here, we’ve defined two color palettes: one for light mode and one for dark mode. Each palette includes primary, secondary, background, and surface colors, as well as corresponding “on” colors for text and icons.

Step 2: Define Your Typography

Next, let’s define a custom typography system. Jetpack Compose uses the Typography class to define text styles. You can create a custom typography system by specifying styles for different text elements, such as headings, body text, and captions.

import androidx.compose.material3.Typography
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp

val CustomTypography = Typography(
    h1 = TextStyle(
        fontFamily = FontFamily.Default,
        fontWeight = FontWeight.Bold,
        fontSize = 32.sp
    ),
    h2 = TextStyle(
        fontFamily = FontFamily.Default,
        fontWeight = FontWeight.Bold,
        fontSize = 24.sp
    ),
    body1 = TextStyle(
        fontFamily = FontFamily.Default,
        fontWeight = FontWeight.Normal,
        fontSize = 16.sp
    ),
    caption = TextStyle(
        fontFamily = FontFamily.Default,
        fontWeight = FontWeight.Normal,
        fontSize = 12.sp
    )
)

In this example, we’ve defined styles for headings (h1 and h2), body text (body1), and captions (caption). You can customize these styles further by adjusting the font family, weight, size, and other properties.

Step 3: Create a Custom Theme

Now that we’ve defined our color palette and typography, we can create a custom theme by wrapping them in a MaterialTheme component. To make our theme dynamic (supporting light and dark modes), we’ll use the LocalContext and Configuration classes to detect the system’s current theme.

import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext

@Composable
fun CustomTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    content: @Composable () -> Unit
) {
    val colors = if (darkTheme) DarkCustomColors else LightCustomColors

    MaterialTheme(
        colorScheme = colors,
        typography = CustomTypography,
        content = content
    )
}

In this CustomTheme composable, we check whether the system is in dark mode using isSystemInDarkTheme(). Based on this, we select the appropriate color palette. We then pass the colors and typography to MaterialTheme, which applies them to all child composables.


Applying the Custom Theme

To use your custom theme, wrap your app’s content in the CustomTheme composable. For example:

import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview

@Composable
fun MyApp() {
    CustomTheme {
        // Your app content goes here
        Greeting("Jetpack Compose")
    }
}

@Composable
fun Greeting(name: String) {
    Text(
        text = "Hello, $name!",
        style = MaterialTheme.typography.h1
    )
}

@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
    MyApp()
}

In this example, the Greeting composable uses the h1 text style from our custom typography. The CustomTheme composable ensures that the correct colors and typography are applied throughout the app.


Advanced Customization

While the above approach works for most apps, you may need more advanced customization in some cases. Here are a few tips for taking your theming to the next level:

  1. Custom Fonts: To use custom fonts, load them as font resources and specify them in your typography styles.
  2. Dynamic Colors: Use the dynamicColorScheme API to adapt your theme to the user’s wallpaper or system settings.
  3. Theme Overrides: Use CompositionLocalProvider to override specific theme properties for a subtree of your UI.
  4. Animations: Add animations to your theme transitions for a more dynamic user experience.

Conclusion

Creating custom themes and typography in Jetpack Compose is a powerful way to align your app’s design with your brand identity and improve the user experience. By defining a custom color palette and typography system, and wrapping your app in a custom theme, you can ensure consistency and maintainability across your UI.

As you continue to explore Jetpack Compose, don’t be afraid to experiment with different design elements and push the boundaries of what’s possible. With its flexible theming system, Compose empowers you to create beautiful, unique, and accessible apps that stand out in the crowded app marketplace.


Last modified 08.03.2025: new content (76eea7a)