Question Details

No question body available.

Tags

android kotlin android-jetpack-compose

Answers (1)

July 30, 2026 Score: 2 Rep: 27,482 Quality: Medium Completeness: 100%

The preview rendering differently between your IDE and your emulator is because you are missing your app's theme composable as the root composable.

The emulated preview just so happens to work because it uses a PreviewActivity activity which does set a background by default as per the system theme, while the IDE preview will not set a default background for your composable unless you set the showBackground parameter in the preview to true:

Screenshot of preview picker with the background-related settings (showBackground and backgroundColor) highlighted

Ideally, your previews and main activity should be adding your app's theme composable to the composable hierarchy.

Adding your app's theme composable as the root composable

When using the Compose-based templates from the new project wizard, a default theme composable is typically generated (typically AppNameTheme) that uses the MaterialTheme composable, along with colour palettes. The Material3 composables you are using (i.e. Text) will then read the colours from this theme composable, or default to a suitable colour if no theme composable exists in the composable hierarchy.

@Composable
fun AppNameTheme(content: @Composable () -> Unit) {
    MaterialTheme(
        colorScheme = / ... /,
        // the new project wizard will likely set other parameters, which are omitted for brevity
        content = content
    )
}

For more information, I would advise checking out the Material Design 3 in Compose documentation, which goes into more detail what the MaterialTheme composable's parameters are.

How the Text composable infers its text colours

Specifically for Text, it first attempts to read the desired text colour to be used in the following order:

  1. Read from the color parameter if it's set to a colour that is not just unspecified (Color.Unspecified)
  2. Read from the textStyle parameter's color property if it's set to a colour that is not unspecified
  3. Read from LocalContentColor, or the initial value Color.Black of this composition local if all else fails
@Composable
fun Text(
  text: String,
  color: Color = Color.Unspecified,
  style: TextStyle = LocalTextStyle.current
  // (other parameters omitted for brevity)
) {
  val textColor = color.takeOrElse { style.color.takeOrElse { LocalContentColor.current } }
  // ...
}

(source)

The source code of the LocalContentColor composition local is as follows:

/
  CompositionLocal containing the preferred content color for a given position in the hierarchy.
  This typically represents the on color for a color in [ColorScheme]. For example, if the
  background color is [ColorScheme.surface], this color is typically set to
  [ColorScheme.onSurface].
 
  This color should be used for any typography / iconography, to ensure that the color of these
  adjusts when the background color changes. For example, on a dark background, text should be
  light, and on a light background, text should be dark.
 
  Defaults to [Color.Black] if no color has been explicitly set.
 */
public val LocalContentColor: ProvidableCompositionLocal = compositionLocalOf { Color.Black }

Because you are:

  • not setting an explicit color, or
  • not setting an explicit textStyle, or
  • not setting a specific LocalContentColor value

It then defaults to Color.Black.

Applying your app's theme

You will have to add your app's theme as the parent composable which should then propagate the relevant colours to your own composables:

@Preview
@Composable
fun PreviewMessageCard() {
    YourAppTheme {
        MessageCard(
            msg = Message("Lexi","Hey, take a look at Jetpack Compose")
        )
    }
}

Alternatively, you can also create a custom preview wrapper (introduced in Compose 1.11.0) which then wraps your content in the app's theme:

class ThemeWrapper: PreviewWrapperProvider {
    @Composable
    override fun Wrap(content: @Composable (() -> Unit)) {
        JetsnackTheme {
            content()
        }
    }
}

@PreviewWrapper(ThemeWrapper::class) @Preview @Composable private fun ButtonPreview() { // JetsnackTheme in effect Button(onClick = {}) { Text(text = "Demo") } }

(This is directly taken from the linked blog post)

Applying it to the activity as well

In previous versions of the IDE, I believe it should by default use the theme composable in your main activity as well, so I suspect they likely removed it in a newer release in favour of the "Navigation UI Activity" template.

Anyways, you will also have to set the app theme in the setContent {} call in your MainActivity:

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // ...

setContent { YourAppTheme { MessageCard(...) } } } }

Setting a background for your components

I would also set a background for your screen-specific components, especially if you want to render it separately from other components.

The foundational composables that are provided by Jetpack Compose (e.g. Row, Column, Box) do not set a background for you, so you will have to either:

The preferred method: Using a Surface

Personally, I would use a Surface composable, or a suitable higher-level Material3 component like a Card in this case, which also adds other convenient stylings like rounded corners and clickable functionality if desired.

But first:

What is a Surface?

The Surface composable provides convenient defaults:

The Surface is responsible for:

  1. Clipping: Surface clips its children to the shape specified by shape
  2. Borders: If shape has a border, then it will also be drawn.
  3. Background: Surface fills the shape specified by shape with the color. If color is ColorScheme.surface a color overlay will be applied. The color of the overlay depends on the tonalElevation of this Surface, and the LocalAbsoluteTonalElevation set by any parent surfaces. This ensures that a Surface never appears to have a lower elevation overlay than its ancestors, by summing the elevation of all previous Surfaces.
  4. Content color: Surface uses contentColor to specify a preferred color for the content of this surface - this is used by the Text and Icon components as a default color.

Note specifically the 3rd and 4th points.

Using the Card composable

Card internally delegates to a Surface, providing all of the defaults as mentioned above.

You can use it as follows:

@Composable
fun MessageCard(modifier: Modifier = Modifier, message: Message) {
    Card(
        modifier = modifier,
    ) {
      // Actual content goes here
    }
}

Alternative methods

Setting a background with the background modifier

You can use the background modifier to specify a background colour.

@Composable
fun MessageCard(modifier: Modifier = Modifier) {
    Row(modifier = modifier.background(...)) {
        // ...
    }
}

Note that Surface uses this internally along with the clip modifier to clip the inner content to the desired shape.


Further reading