Using Custom Fonts in KMP (Compose Multiplatform)

Bharat Kumar
3 min readJan 12, 2024

--

Hi all the KMP developers.

Well, do you want to use fonts in your Compose Multiplatform Project?

Let’s Skip the shit and let's see how it's done.

Let’s Start with downloading the fonts here.

Here I have downloaded Montserrat Alternates

Now add them to your commonMain/resources/font directory and change the names as they should not contain capitals and spaces.

Fonts added in commonMain/resources/font directory image
Guess the theme I am Using

Not enable resource support by adding the following experimental library dependency. Note that it requires you to opt in for usage.

commonMain.dependencies {
// other common dependencies
@OptIn(ExperimentalComposeLibrary::class)
implementation(compose.components.resources)
}

After that make sure you add the common resources to your Android source sets. This has been the issue for Compose Multiplatform's latest version hope it gets fixed

android {
sourceSets["main"].res.srcDirs("src/commonMain/resources", "src/androidMain/res")
sourceSets["main"].resources.srcDirs("src/commonMain/resources")
}

Now let's start the actual work

Create an expect composable function that will take a string or resource name and return a Font

@Composable
expect fun font(
name: String,
res: String,
weight: FontWeight,
style: FontStyle
): Font

Now add your actual definitions for different sources as shown

Android

@Composable
actual fun font(
name: String,
res: String,
weight: FontWeight,
style: FontStyle
): Font {
val context = LocalContext.current
val id = context.resources.getIdentifier(res, "font", context.packageName)
return Font(id, weight, style)
}

IOS

private val cache: MutableMap<String, Font> = mutableMapOf()
@OptIn(ExperimentalResourceApi::class)
@Composable
actual fun font(
name: String,
res: String,
weight: FontWeight,
style: FontStyle
): Font {
return cache.getOrPut(res) {
val byteArray = runBlocking {
resource("font/$res.ttf").readBytes()
}
Font(res, byteArray, weight, style)
}
}

Desktop

@Composable
actual fun font(
name: String,
res: String,
weight: FontWeight,
style: FontStyle
): Font = Font("font/$res.ttf", weight, style)

Note for IOS and Desktop you have to add the platform Font import

import androidx.compose.ui.text.platform.Font

Now let’s see how to use them in our Material Theme like we generally do in Android

@Composable
fun getTypography(): Typography {
val Montserrat = FontFamily(
font(
name = "Mons Bold",
res = "mons_bold",
weight = FontWeight.Bold,
style = FontStyle.Normal
),
font(
name = "Mons Semibold",
res = "mons_semibold",
weight = FontWeight.SemiBold,
style = FontStyle.Normal
)
)

return Typography(
h1 = TextStyle(
fontFamily = Montserrat,
fontSize = 38.sp,
fontWeight = FontWeight.Bold,
),
body1 = TextStyle(
fontFamily = Montserrat,
fontSize = 14.sp,
fontWeight = FontWeight.Normal,
)
)

This will be your Typo.kt file in your themes

@Composable
fun MyAppTheme(
content: @Composable () -> Unit,
) {
MaterialTheme(
colors = myColors,
content = content,
typography = getTypography()
)
}

And this is how you can use it in your theme or you can directly use the Style in your composables.

Hope this article helped you with using custom fonts easily without hassle in your Kotlin Multiplatform Application

Checkout Kashif Mehmood’s https://github.com/Kashif-E/KMPMovies for clear implementation

Update — The compose multi-platform resource Library has been updated and it’s really easy to use and you can use fonts easily.

If you like this a clap would mean a lot :)

--

--

Bharat Kumar
Bharat Kumar

Written by Bharat Kumar

Indian Android Developer || Kotlin Enthusiast

No responses yet