'Android Jetpack Compose white TabRow

I am trying to get Tabs working with a TabRow on Android with compose. What I'd like is the TabRow to have a white background. The default color seems to be this purple(ish) as shown in the documentation (https://developer.android.com/reference/kotlin/androidx/compose/material/package-summary).

When I set backgroundColor to White the Tabs are grey for some reason.

How would you achieve white Tabs in Compose?

Thanks!



Solution 1:[1]

EDIT: Google have now fixed this issue: https://issuetracker.google.com/issues/197254738. Hopefully it will find its way into a JC release soon!

Question's a couple of months old, but recently encountered this issue so others might find these solutions useful:

Solution 0 (quickest)

Don't have a divider. For example:

TabRow(
    selectedTabIndex = ...,
    modifier = Modifier.height(100.dp).fillMaxWidth(),
    divider = {}
) { /* content here */ }

Solution 1

Since the TabRow is just a container, don't specify a height in its modifier. If you want it to have a custom height, instead make sure that each of the Tabs have their heights specified explicitly. For example:

var selectedTabIndex by remember { mutableStateOf(0) }

TabRow(
    selectedTabIndex = selectedTabIndex,
    modifier = Modifier.fillMaxWidth(), // Don't specify the TabRow's height!
    backgroundColor = Colors.White
) {
    listOf("Hello", "World").forEachIndexed { i, text ->
        Tab(
            selected = selectedTabIndex == i,
            onClick = { selectedTabIndex = i },
            modifier = Modifier.height(50.dp), // Specify the Tab's height instead
            text = { Text(text) }
        )
    }
}

Solution 2

Force the divider to only draw at the bottom of the layout. This is consistent with the default indicator implementation.

TabRow(
    selectedTabIndex = ...,
    modifier = Modifier.height(100.dp).fillMaxWidth(),
    backgroundColor = Colors.White,
    divider = { TabRowDefaults.Divider(Modifier.wrapContentSize(Alignment.BottomStart)) },
) { /* content here */ }

Explanation

From the source code here and here, the default divider has height 1dp. However, the OP is seeing a grey background because the divider is drawing over the whole TabRow!

When you specify a height constraint on a TabRow, the constraint gets passed through to the divider (source code here). The divider therefore takes up the entire height of the TabRow – in OP's case, the divider is a transparent grey colour, so it makes the TabRow look grey. The above solutions have a few different ways to solve the problem:

  1. Removing the divider removes the issue!
  2. TabRows wrap their tabs, so an alternative solution is to give the TabRow height by specifying the tabs' heights rather than the TabRow's.
  3. This forces the divider to ignore the TabRow's height constraint, and instead draw itself at its correct height at the BottomStart position in the TabRow.

Solution 2:[2]

You can set color using backgroundColor: Color = MaterialTheme.colors.primarySurface,.

(For Documentation read this)

Sample code below:

@Composable
fun TabRow(
    selectedTabIndex: Int,
    modifier: Modifier = Modifier,
    backgroundColor: Color = MaterialTheme.colors.primarySurface,
    contentColor: Color = contentColorFor(backgroundColor),
    indicator: (List<TabPosition>) -> Unit = @Composable { tabPositions ->
        TabRowDefaults.Indicator(
            Modifier.tabIndicatorOffset(tabPositions[selectedTabIndex])
        )
    },
    divider: () -> Unit = @Composable {
        TabRowDefaults.Divider()
    },
    tabs: () -> Unit
): @Composable Unit

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 dumbfingers
Solution 2 minchaej