Use tabs for switching between related views without leaving the current screen.
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.widthIn
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.unit.dp
import com.composables.icons.lucide.BookOpen
import com.composables.icons.lucide.Code
import com.composables.icons.lucide.Eye
import com.composables.icons.lucide.Lucide
import com.composables.ui.components.Icon
import com.composables.ui.components.Tab
import com.composables.ui.components.TabList
import com.composables.ui.components.TabOrientation
import com.composables.ui.components.TabPanel
import com.composables.ui.components.Text
import com.composables.ui.components.Tabs
@Composable
fun TabsExample() {
val tabs = listOf("Preview", "Code", "Docs")
var selected by remember { mutableStateOf(tabs.first()) }
Tabs(
selectedTab = selected,
onSelectedTabChange = { selected = it },
orderedTabs = tabs,
) {
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
) {
TabList {
tabs.forEach { tab ->
Tab(key = tab, text = { Text(tab) })
}
}
tabs.forEach { tab ->
TabPanel(tab) {
Text("$tab content")
}
}
}
}
}Installation
implementation("com.composables:ui:0.1.0")Add the required dependencies
implementation("com.composables:composeunstyled:2.7.0")
Copy and paste the following sources into your project
components/Tabs.kt
package com.composables.ui.components
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.tween
import androidx.compose.foundation.Indication
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateMapOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.LayoutCoordinates
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
import com.composables.ui.theme.InteractionMode
import com.composables.ui.theme.LocalInteractionMode
import com.composables.ui.theme.alphas
import com.composables.ui.theme.borderColor
import com.composables.ui.theme.colors
import com.composables.ui.theme.defaultIndication
import com.composables.ui.theme.disabledAlpha
import com.composables.ui.theme.ringColor
import com.composables.ui.theme.indications
import com.composables.ui.theme.mutedColor
import com.composables.ui.theme.primaryColor
import com.composeunstyled.LocalTextStyle
import com.composeunstyled.ProvideContentColor
import com.composeunstyled.ProvideTextStyle
import com.composeunstyled.Stack
import com.composeunstyled.StackOrientation
import com.composeunstyled.StackScope
import com.composeunstyled.UnstyledTab
import com.composeunstyled.UnstyledTabGroup as UnstyledTabs
import com.composeunstyled.UnstyledTabList
import com.composeunstyled.UnstyledTabPanel
import com.composeunstyled.buildModifier
import com.composeunstyled.theme.Theme
import kotlin.jvm.JvmInline
class TabsScope<T> internal constructor(
internal val selectedTab: T,
internal val orderedTabs: List<T>,
)
/**
* An individual tab inside a tab list.
* @param key Key represented by this tab or tab panel.
* @param modifier Modifier applied to the component.
* @param enabled Whether the tab can be interacted with.
* @param activateOnFocus Whether focusing the tab should immediately select it.
* @param interactionSource Interaction source used for focus, hover, and press state.
* @param indication Indication used when the tab is pressed or focused.
* @param icon Optional icon content shown before the tab text.
* @param text Text content shown inside the tab.
*/
@Composable
fun <T> Tab(
key: T,
modifier: Modifier = Modifier,
enabled: Boolean = true,
activateOnFocus: Boolean = true,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
indication: Indication? = Theme[indications][defaultIndication],
icon: (@Composable () -> Unit)? = null,
text: @Composable () -> Unit,
) {
val shape = RoundedCornerShape(4.dp)
val updateTabIndicatorBounds = LocalTabIndicatorBoundsUpdater.current
UnstyledTab(
key = key,
enabled = enabled,
activateOnFocus = activateOnFocus,
interactionSource = interactionSource,
indication = indication,
contentAlignment = Alignment.Center,
modifier = modifier
.then(buildModifier {
if (updateTabIndicatorBounds != null) {
add(Modifier.onGloballyPositioned { updateTabIndicatorBounds(key, it) })
}
if (!enabled) add(Modifier.alpha(Theme[alphas][disabledAlpha]))
})
.focusRing(
interactionSource = interactionSource,
color = Theme[colors][ringColor],
shape = shape,
)
.bouncyPress(
interactionSource = interactionSource,
enabled = enabled,
)
.clip(shape),
) {
Row(
modifier = Modifier
.heightIn(min = tabMinHeight())
.padding(horizontal = TabContentHorizontalPadding),
horizontalArrangement = Arrangement.spacedBy(2.dp),
verticalAlignment = Alignment.CenterVertically,
) {
ProvideContentColor(if (selected) Theme[colors][primaryColor] else Theme[colors][mutedColor]) {
if (icon != null) {
Box(
modifier = Modifier.size(TabIconSize),
contentAlignment = Alignment.Center,
) {
icon()
}
Box(Modifier.width(TabIconSpacing))
}
ProvideTextStyle(LocalTextStyle.current.merge(TabTextStyle)) {
text()
}
}
}
}
}
/**
* Orientation options for arranging tab lists.
*/
@JvmInline
value class TabOrientation internal constructor(internal val orientation: Orientation) {
companion object {
/**
* Arranges tabs in a horizontal row.
*/
val Horizontal = TabOrientation(Orientation.Horizontal)
/**
* Arranges tabs in a vertical column.
*/
val Vertical = TabOrientation(Orientation.Vertical)
}
}
/**
* Tabs that coordinate tab triggers and panels.
* @param selectedTab Currently selected tab key.
* @param onSelectedTabChange Called when the selected tab changes.
* @param orderedTabs Ordered list of tab keys used for indicator placement and navigation.
* @param modifier Modifier applied to the component.
* @param content Composable content displayed by the component.
*/
@Composable
fun <T> Tabs(
selectedTab: T,
onSelectedTabChange: (T) -> Unit,
orderedTabs: List<T>,
modifier: Modifier = Modifier,
content: @Composable TabsScope<T>.() -> Unit,
) {
UnstyledTabs(selectedTab, onSelectedTabChange, orderedTabs, modifier) {
TabsScope(
selectedTab = selectedTab,
orderedTabs = orderedTabs,
).content()
}
}
/**
* A container that arranges tab triggers and draws the active indicator.
* @param modifier Modifier applied to the component.
* @param orientation Orientation used to lay out the tab list.
* @param dividerColor Color used for the indicator divider line.
* @param content Composable content displayed by the component.
*/
@Composable
fun <T> TabsScope<T>.TabList(
modifier: Modifier = Modifier,
orientation: TabOrientation = TabOrientation.Horizontal,
dividerColor: Color = Theme[colors][borderColor],
content: @Composable StackScope.() -> Unit,
) {
val tabIndicatorBoundsByKey = remember { mutableStateMapOf<Any?, TabIndicatorBounds>() }
var indicatorContainerCoordinates by remember { mutableStateOf<LayoutCoordinates?>(null) }
var indicatorContainerSize by remember { mutableStateOf(IntSize.Zero) }
val density = LocalDensity.current
val updateTabIndicatorBounds: (Any?, LayoutCoordinates) -> Unit = { key, tabCoordinates ->
val containerCoordinates = indicatorContainerCoordinates
if (containerCoordinates != null && containerCoordinates.isAttached && tabCoordinates.isAttached) {
if (orderedTabs.contains(key)) {
val tabPosition = containerCoordinates.localPositionOf(tabCoordinates, Offset.Zero)
tabIndicatorBoundsByKey[key] = with(density) {
if (orientation == TabOrientation.Horizontal) {
TabIndicatorBounds(
start = tabPosition.x.toDp(),
size = tabCoordinates.size.width.toDp(),
)
} else {
TabIndicatorBounds(
start = tabPosition.y.toDp(),
size = tabCoordinates.size.height.toDp(),
)
}
}
}
}
}
val indicatorBounds = resolveTabIndicatorBounds(
selectedTab = selectedTab,
tabBoundsByKey = tabIndicatorBoundsByKey,
)
val tabListWidth = with(density) { indicatorContainerSize.width.toDp() }
val tabListHeight = with(density) { indicatorContainerSize.height.toDp() }
if (orientation == TabOrientation.Horizontal) {
Column(modifier = modifier) {
Box(
modifier = Modifier.onGloballyPositioned {
indicatorContainerCoordinates = it
indicatorContainerSize = it.size
},
) {
UnstyledTabList(
orientation = orientation.orientation,
) {
Stack(orientation = orientation.toStackOrientation()) {
TabIndicatorBoundsProvider(updateTabIndicatorBounds) {
content()
}
}
}
}
Spacer(Modifier.height(TabListBottomPadding))
TabIndicatorLine(
modifier = Modifier.width(tabListWidth),
bounds = indicatorBounds,
dividerColor = dividerColor,
)
}
} else {
Row(modifier = modifier.height(IntrinsicSize.Min)) {
Box(
modifier = Modifier.onGloballyPositioned {
indicatorContainerCoordinates = it
indicatorContainerSize = it.size
},
) {
UnstyledTabList(
orientation = orientation.orientation,
) {
Stack(orientation = orientation.toStackOrientation()) {
TabIndicatorBoundsProvider(updateTabIndicatorBounds) {
content()
}
}
}
}
Spacer(Modifier.width(TabListBottomPadding))
VerticalTabIndicatorLine(
modifier = Modifier.height(tabListHeight),
bounds = indicatorBounds,
dividerColor = dividerColor,
)
}
}
}
private fun TabOrientation.toStackOrientation(): StackOrientation {
return if (this == TabOrientation.Horizontal) StackOrientation.Horizontal else StackOrientation.Vertical
}
private val LocalTabIndicatorBoundsUpdater =
androidx.compose.runtime.compositionLocalOf<((Any?, LayoutCoordinates) -> Unit)?> { null }
@Composable
private fun TabIndicatorBoundsProvider(
updateTabIndicatorBounds: ((Any?, LayoutCoordinates) -> Unit)? = null,
content: @Composable () -> Unit,
) {
androidx.compose.runtime.CompositionLocalProvider(
LocalTabIndicatorBoundsUpdater provides updateTabIndicatorBounds,
) {
content()
}
}
@Composable
private fun TabIndicatorLine(
modifier: Modifier = Modifier,
bounds: TabIndicatorBounds?,
dividerColor: Color,
) {
val placedBounds = placedTabIndicatorBounds(
bounds = bounds,
startLabel = "TabIndicatorStart",
sizeLabel = "TabIndicatorWidth",
)
Box(
modifier = modifier
.height(TabIndicatorHeight)
.background(dividerColor, TabIndicatorShape),
) {
if (bounds != null) {
Box(
modifier = Modifier
.offset(x = placedBounds.start)
.width(placedBounds.size)
.height(TabIndicatorHeight)
.background(
color = Theme[colors][primaryColor],
shape = TabIndicatorShape,
),
)
}
}
}
@Composable
private fun VerticalTabIndicatorLine(
modifier: Modifier = Modifier,
bounds: TabIndicatorBounds?,
dividerColor: Color,
) {
val placedBounds = placedTabIndicatorBounds(
bounds = bounds,
startLabel = "VerticalTabIndicatorStart",
sizeLabel = "VerticalTabIndicatorHeight",
)
Box(
modifier = modifier
.width(TabIndicatorHeight)
.background(dividerColor, TabIndicatorShape),
) {
if (bounds != null) {
Box(
modifier = Modifier
.offset(y = placedBounds.start)
.width(TabIndicatorHeight)
.height(placedBounds.size)
.background(
color = Theme[colors][primaryColor],
shape = TabIndicatorShape,
),
)
}
}
}
@Composable
private fun placedTabIndicatorBounds(
bounds: TabIndicatorBounds?,
startLabel: String,
sizeLabel: String,
): TabIndicatorBounds {
var initialBoundsPlaced by remember { mutableStateOf(false) }
if (bounds == null) {
SideEffect { initialBoundsPlaced = false }
return TabIndicatorBounds(start = 0.dp, size = 0.dp)
}
if (!initialBoundsPlaced) {
SideEffect { initialBoundsPlaced = true }
return bounds
}
return TabIndicatorBounds(
start = animateTabIndicatorDp(bounds.start, startLabel),
size = animateTabIndicatorDp(bounds.size, sizeLabel),
)
}
@Composable
private fun animateTabIndicatorDp(
targetValue: Dp,
label: String,
): Dp {
val animatedValue by animateDpAsState(
targetValue = targetValue,
animationSpec = tween(durationMillis = 180),
label = label,
)
return animatedValue
}
private fun resolveTabIndicatorBounds(
selectedTab: Any?,
tabBoundsByKey: Map<Any?, TabIndicatorBounds>,
): TabIndicatorBounds? {
return tabBoundsByKey[selectedTab]
}
private data class TabIndicatorBounds(
val start: Dp,
val size: Dp,
)
private val TabTextStyle = TextStyle(
fontWeight = FontWeight.SemiBold,
)
private val TabContentHorizontalPadding = 12.dp
private val TabIconSize = 24.dp
private val TabIconSpacing = 8.dp
private val TabIndicatorHeight = 1.dp
private val TabIndicatorShape = RoundedCornerShape(100)
private val TabListBottomPadding = 2.dp
@Composable
private fun tabMinHeight(): Dp {
return if (LocalInteractionMode.current == InteractionMode.Touch) 48.dp else 36.dp
}
/**
* Content associated with a specific tab key.
* @param key Key represented by this tab or tab panel.
* @param modifier Modifier applied to the component.
* @param content Composable content displayed by the component.
*/
@Composable
fun <T> TabsScope<T>.TabPanel(
key: T,
modifier: Modifier = Modifier,
content: @Composable () -> Unit,
) {
UnstyledTabPanel(key = key, modifier = modifier) {
content()
}
}components/Utils.kt
package com.composables.ui.components
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.spring
import androidx.compose.animation.core.tween
import androidx.compose.foundation.interaction.InteractionSource
import androidx.compose.foundation.interaction.collectIsFocusedAsState
import androidx.compose.foundation.interaction.collectIsPressedAsState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.composables.ui.theme.colors
import com.composables.ui.theme.ringColor
import com.composeunstyled.FocusRingVisibility
import com.composeunstyled.collectIsFocusVisibleAsState
import com.composeunstyled.outline
import com.composeunstyled.theme.Theme
@Composable
fun Modifier.focusRing(
interactionSource: InteractionSource,
width: Dp = 2.dp,
color: Color = Theme[colors][ringColor],
shape: Shape = RectangleShape,
offset: Dp = 0.dp,
visibility: FocusRingVisibility = FocusRingVisibility.FocusVisible,
): Modifier {
val showFocusRing by if (visibility == FocusRingVisibility.FocusVisible) {
interactionSource.collectIsFocusVisibleAsState()
} else {
interactionSource.collectIsFocusedAsState()
}
val animatedWidth by animateDpAsState(
targetValue = if (showFocusRing) width else 0.dp,
animationSpec = tween(durationMillis = 120),
label = "FocusRingWidth",
)
return this then Modifier.outline(
width = animatedWidth,
color = color,
shape = shape,
offset = offset,
)
}
@Composable
fun Modifier.bouncyPress(
interactionSource: InteractionSource,
enabled: Boolean = true,
pressedScale: Float = 0.98f,
): Modifier {
val pressed by interactionSource.collectIsPressedAsState()
val scale by animateFloatAsState(
targetValue = if (enabled && pressed) pressedScale else 1f,
animationSpec = spring(
dampingRatio = Spring.DampingRatioMediumBouncy,
stiffness = Spring.StiffnessMediumLow,
),
label = "BouncyPressScale",
)
return this then Modifier.graphicsLayer {
scaleX = scale
scaleY = scale
}
}Examples
Weighted
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.composables.ui.components.Tab
import com.composables.ui.components.TabList
import com.composables.ui.components.TabPanel
import com.composables.ui.components.Tabs
import com.composables.ui.components.Text
@Composable
fun WeightedTabsExample() {
val tabs = listOf("Preview", "Code", "Docs")
var selected by remember { mutableStateOf(tabs.first()) }
Tabs(
selectedTab = selected,
onSelectedTabChange = { selected = it },
orderedTabs = tabs,
) {
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
) {
TabList(modifier = Modifier.fillMaxWidth()) {
tabs.forEach { tab ->
Tab(
key = tab,
modifier = Modifier.weight(1f),
text = {
Text(tab)
},
)
}
}
tabs.forEach { tab ->
TabPanel(tab) {
Text("$tab content")
}
}
}
}
}With icons
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.unit.dp
import com.composables.icons.lucide.BookOpen
import com.composables.icons.lucide.Code
import com.composables.icons.lucide.Eye
import com.composables.icons.lucide.Lucide
import com.composables.ui.components.Icon
import com.composables.ui.components.Tab
import com.composables.ui.components.TabList
import com.composables.ui.components.TabPanel
import com.composables.ui.components.Tabs
import com.composables.ui.components.Text
@Composable
fun TabsWithIconsExample() {
val tabs = listOf(
TabsExampleTab("Preview", Lucide.Eye),
TabsExampleTab("Code", Lucide.Code),
TabsExampleTab("Docs", Lucide.BookOpen),
)
var selected by remember { mutableStateOf(tabs.first()) }
Tabs(
selectedTab = selected,
onSelectedTabChange = { selected = it },
orderedTabs = tabs,
) {
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
) {
TabList {
tabs.forEach { tab ->
Tab(
key = tab,
icon = {
Icon(
imageVector = tab.icon,
contentDescription = null,
modifier = Modifier.size(20.dp),
)
},
text = {
Text(tab.label)
},
)
}
}
tabs.forEach { tab ->
TabPanel(tab) {
Text("${tab.label} content")
}
}
}
}
}
private data class TabsExampleTab(
val label: String,
val icon: ImageVector,
)Vertical
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.widthIn
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.composables.ui.components.Tab
import com.composables.ui.components.TabList
import com.composables.ui.components.TabOrientation
import com.composables.ui.components.TabPanel
import com.composables.ui.components.Tabs
import com.composables.ui.components.Text
@Composable
fun VerticalTabsExample() {
val tabs = listOf("Preview", "Code", "Docs")
var selected by remember { mutableStateOf(tabs.first()) }
Tabs(
selectedTab = selected,
onSelectedTabChange = { selected = it },
orderedTabs = tabs,
modifier = Modifier.fillMaxWidth(),
) {
Row(
modifier = Modifier
.widthIn(max = 420.dp)
.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(16.dp),
) {
TabList(orientation = TabOrientation.Vertical) {
tabs.forEach { tab ->
Tab(key = tab, text = { Text(tab) })
}
}
tabs.forEach { tab ->
TabPanel(
key = tab,
modifier = Modifier.weight(1f),
) {
Text("$tab content")
}
}
}
}
}Disabled
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.unit.dp
import com.composables.ui.components.Tab
import com.composables.ui.components.TabList
import com.composables.ui.components.TabPanel
import com.composables.ui.components.Tabs
import com.composables.ui.components.Text
@Composable
fun DisabledTabsExample() {
val tabs = listOf("Preview", "Code", "Docs")
var selected by remember { mutableStateOf(tabs.first()) }
Tabs(
selectedTab = selected,
onSelectedTabChange = { selected = it },
orderedTabs = tabs,
) {
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
) {
TabList {
tabs.forEach { tab ->
Tab(
key = tab,
enabled = tab != "Code",
text = { Text(tab) },
)
}
}
tabs.forEach { tab ->
TabPanel(tab) {
Text("$tab content")
}
}
}
}
}API Reference
Tabs
Tabs that coordinate tab triggers and panels.
@Composable
fun <T> Tabs(
selectedTab: T,
onSelectedTabChange: (T) -> Unit,
orderedTabs: List<T>,
modifier: Modifier = Modifier,
content: @Composable TabsScope<T>.() -> Unit,
)
| Parameter | Type | Description |
|---|---|---|
selectedTab |
T |
Currently selected tab key. |
onSelectedTabChange |
(T) -> Unit |
Called when the selected tab changes. |
orderedTabs |
List<T> |
Ordered list of tab keys used for indicator placement and navigation. |
modifier |
Modifier |
Modifier applied to the component. |
content |
@Composable TabsScope<T>.() -> Unit |
Composable content displayed by the component. |
Tab
An individual tab inside a tab list.
@Composable
fun <T> Tab(
key: T,
modifier: Modifier = Modifier,
enabled: Boolean = true,
activateOnFocus: Boolean = true,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
indication: Indication? = Theme[indications][defaultIndication],
icon: (@Composable () -> Unit)? = null,
text: @Composable () -> Unit,
)
| Parameter | Type | Description |
|---|---|---|
key |
T |
Key represented by this tab or tab panel. |
modifier |
Modifier |
Modifier applied to the component. |
enabled |
Boolean |
Whether the tab can be interacted with. |
activateOnFocus |
Boolean |
Whether focusing the tab should immediately select it. |
interactionSource |
MutableInteractionSource |
Interaction source used for focus, hover, and press state. |
indication |
Indication? |
Indication used when the tab is pressed or focused. |
icon |
(@Composable () -> Unit)? |
Optional icon content shown before the tab text. |
text |
@Composable () -> Unit |
Text content shown inside the tab. |
TabList
A container that arranges tab triggers and draws the active indicator.
@Composable
fun <T> TabsScope<T>.TabList(
modifier: Modifier = Modifier,
orientation: TabOrientation = TabOrientation.Horizontal,
dividerColor: Color = Theme[colors][borderColor],
content: @Composable StackScope.() -> Unit,
)
| Parameter | Type | Description |
|---|---|---|
modifier |
Modifier |
Modifier applied to the component. |
orientation |
TabOrientation |
Orientation used to lay out the tab list. |
dividerColor |
Color |
Color used for the indicator divider line. |
content |
@Composable StackScope.() -> Unit |
Composable content displayed by the component. |
TabPanel
Content associated with a specific tab key.
@Composable
fun <T> TabsScope<T>.TabPanel(
key: T,
modifier: Modifier = Modifier,
content: @Composable () -> Unit,
)
| Parameter | Type | Description |
|---|---|---|
key |
T |
Key represented by this tab or tab panel. |
modifier |
Modifier |
Modifier applied to the component. |
content |
@Composable () -> Unit |
Composable content displayed by the component. |
TabOrientation
Orientation options for arranging tab lists.
@JvmInline
value class TabOrientation internal constructor(internal val orientation: Orientation)
| Value | Description |
|---|---|
Horizontal |
Arranges tabs in a horizontal row. |
Vertical |
Arranges tabs in a vertical column. |