Cards
Cardsanimated

Video Chapters

Video card listing chapter markers with the current segment highlighted.

Chapters
Intro00:00
Setup04:12
Demo11:30

Installation

caveui components are copy-paste Jetpack Compose built entirely on Material 3 — there's no caveui dependency to add. Make sure Material 3 is on your classpath (it ships with the Compose BOM), then copy the Usage snippet below into your project.

kotlin
// build.gradle.kts (module)
dependencies {
    implementation(platform("androidx.compose:compose-bom:2025.06.00"))
    implementation("androidx.compose.material3:material3")
}

Usage

kotlin
@Composable
fun VideoChapters(chapters: List<Pair<String, Float>>) {
  Card(
    shape = RoundedCornerShape(18.dp),
    modifier = Modifier.fillMaxWidth(),
  ) {
    Column(Modifier.padding(16.dp)) {
      Row(verticalAlignment = Alignment.CenterVertically) {
        Icon(Icons.Default.Movie, contentDescription = null)
        Spacer(Modifier.width(8.dp))
        Text("Chapters",
          style = MaterialTheme.typography.titleMedium)
      }
      Spacer(Modifier.height(12.dp))
      val active = 1
      chapters.forEachIndexed { i, (label, at) ->
        val on = i == active
        val bg by animateColorAsState(
          targetValue = if (on)
            MaterialTheme.colorScheme.primaryContainer
          else Color.Transparent,
          label = "ch$i",
        )
        Row(
          verticalAlignment = Alignment.CenterVertically,
          modifier = Modifier
            .fillMaxWidth()
            .clip(RoundedCornerShape(10.dp))
            .background(bg)
            .padding(10.dp),
        ) {
          Icon(
            Icons.Default.PlayArrow,
            contentDescription = null,
            tint = if (on)
              MaterialTheme.colorScheme.primary
            else MaterialTheme.colorScheme.onSurfaceVariant,
          )
          Spacer(Modifier.width(10.dp))
          Text(label, Modifier.weight(1f))
          Text(
            "${(at * 100).toInt()}:00",
            style = MaterialTheme.typography.labelSmall,
          )
        }
      }
    }
  }
}