Back to Blog

Custom Color Schemes, Typography & Shapes in Kotlin Desktop | Lesson 6

Sandy LaneSandy Lane

Video: Custom Color Schemes, Typography & Shapes in Kotlin Desktop | Lesson 6 by Taught by Celeste AI - AI Coding Coach

Watch full page →

Custom Color Schemes, Typography & Shapes in Kotlin Desktop

In this lesson, you’ll learn how to create a dynamic theme dashboard in Kotlin Compose Desktop by defining custom color schemes, typography styles, and shapes. The example demonstrates switching between light and dark modes at runtime using mutable state and MaterialTheme components.

Code

import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.*
import androidx.compose.material3.icons.Icons
import androidx.compose.material3.icons.filled.DarkMode
import androidx.compose.material3.icons.filled.LightMode
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp

// Define light and dark color schemes
private val LightColors = lightColorScheme(
  primary = 0xFF6200EE.toInt().toColor(),
  secondary = 0xFF03DAC6.toInt().toColor(),
  background = 0xFFFFFFFF.toInt().toColor(),
  surface = 0xFFFFFFFF.toInt().toColor(),
  onPrimary = 0xFFFFFFFF.toInt().toColor(),
  onSecondary = 0xFF000000.toInt().toColor()
)

private val DarkColors = darkColorScheme(
  primary = 0xFFBB86FC.toInt().toColor(),
  secondary = 0xFF03DAC6.toInt().toColor(),
  background = 0xFF121212.toInt().toColor(),
  surface = 0xFF121212.toInt().toColor(),
  onPrimary = 0xFF000000.toInt().toColor(),
  onSecondary = 0xFF000000.toInt().toColor()
)

// Custom typography styles
private val AppTypography = Typography(
  headlineLarge = TextStyle(
    fontFamily = FontFamily.Serif,
    fontWeight = FontWeight.Bold,
    fontSize = 30.sp
  ),
  titleMedium = TextStyle(
    fontFamily = FontFamily.SansSerif,
    fontWeight = FontWeight.SemiBold,
    fontSize = 20.sp
  ),
  bodyLarge = TextStyle(
    fontFamily = FontFamily.Monospace,
    fontWeight = FontWeight.Normal,
    fontSize = 16.sp
  ),
  labelMedium = TextStyle(
    fontFamily = FontFamily.Default,
    fontWeight = FontWeight.Light,
    fontSize = 12.sp
  )
)

// Custom shapes for components
private val AppShapes = Shapes(
  small = RoundedCornerShape(4.dp),
  medium = RoundedCornerShape(8.dp),
  large = RoundedCornerShape(12.dp)
)

// Composable theme wrapper switching colors, typography, and shapes
@Composable
fun AppTheme(
  darkTheme: Boolean,
  content: @Composable () -> Unit
) {
  val colors = if (darkTheme) DarkColors else LightColors

  MaterialTheme(
    colorScheme = colors,
    typography = AppTypography,
    shapes = AppShapes,
    content = content
  )
}

// Example usage with a runtime light/dark toggle
@Composable
fun ThemeDashboard() {
  var isDarkTheme by remember { mutableStateOf(false) }

  AppTheme(darkTheme = isDarkTheme) {
    Column(
      modifier = Modifier.fillMaxSize().padding(16.dp),
      verticalArrangement = Arrangement.spacedBy(16.dp)
    ) {
      Text("Theme Dashboard", style = MaterialTheme.typography.headlineLarge)

      IconButton(onClick = { isDarkTheme = !isDarkTheme }) {
        Icon(
          imageVector = if (isDarkTheme) Icons.Filled.LightMode else Icons.Filled.DarkMode,
          contentDescription = "Toggle Theme"
        )
      }

      Surface(
        shape = MaterialTheme.shapes.medium,
        tonalElevation = 4.dp,
        modifier = Modifier.fillMaxWidth().height(100.dp)
      ) {
        Box(Modifier.fillMaxSize()) {
          Text("This surface uses custom shapes and colors",
            style = MaterialTheme.typography.bodyLarge,
            modifier = Modifier.padding(16.dp))
        }
      }
    }
  }
}

Key Points

  • Use darkColorScheme() and lightColorScheme() to define colors for dark and light themes.
  • Create custom typography by specifying TextStyle with font family, weight, and size for different text roles.
  • Define shapes using RoundedCornerShape for consistent corner radii across UI components.
  • Wrap your UI in a composable AppTheme that provides colors, typography, and shapes via MaterialTheme.
  • Toggle themes at runtime using mutableStateOf and update UI reactively with Compose.