Blocks

Crypto Swap

A token-swap screen with pay and receive cards, a flip toggle, fee details and a slide-to-confirm action.

9:41
8

Swap

You Pay52.34 BNBMax
BBNB0.01

≈ 6,247.70 USD

You Receive187.52 USDT
TUSDT6.7345108344

≈ 28,197.64 USD

🔥 Fee: 0.255851 USDT

1 BNB = 673.45108 (198,98 USD)

Slide to Swap›››

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
data class Token(val symbol: String, val amount: String, val usd: String)

@Composable
fun SwapScreen(pay: Token, receive: Token, fee: String, onSwap: () -> Unit) {
    Column(
        Modifier.fillMaxSize()
            .background(MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.3f))
            .padding(16.dp),
    ) {
        Text("Swap", Modifier.fillMaxWidth(), textAlign = TextAlign.Center,
            style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.Bold)
        Spacer(Modifier.height(12.dp))
        TokenCard("You Pay", pay)
        Box(Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) {
            Surface(shape = CircleShape, color = MaterialTheme.colorScheme.background,
                modifier = Modifier.size(36.dp).offset(y = (-8).dp)) {
                Box(contentAlignment = Alignment.Center) {
                    Icon(Icons.Filled.SwapVert, "Flip")
                }
            }
        }
        TokenCard("You Receive", receive)
        Spacer(Modifier.height(8.dp))
        Text("Fee: $fee", Modifier.fillMaxWidth(), textAlign = TextAlign.Center,
            style = MaterialTheme.typography.labelMedium,
            color = MaterialTheme.colorScheme.onSurfaceVariant)
        Spacer(Modifier.weight(1f))
        Surface(color = MaterialTheme.colorScheme.onBackground, shape = CircleShape,
            modifier = Modifier.fillMaxWidth().clickable { onSwap() }) {
            Row(Modifier.padding(6.dp), verticalAlignment = Alignment.CenterVertically) {
                Surface(shape = CircleShape, color = MaterialTheme.colorScheme.background,
                    modifier = Modifier.size(36.dp)) {
                    Box(contentAlignment = Alignment.Center) { Icon(Icons.Filled.Check, null) }
                }
                Text("Slide to Swap", Modifier.weight(1f), textAlign = TextAlign.Center,
                    color = MaterialTheme.colorScheme.background, fontWeight = FontWeight.SemiBold)
            }
        }
    }
}

@Composable
private fun TokenCard(label: String, token: Token) {
    Surface(color = MaterialTheme.colorScheme.background, shape = RoundedCornerShape(16.dp),
        modifier = Modifier.fillMaxWidth()) {
        Column(Modifier.padding(16.dp)) {
            Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
                Text(label, style = MaterialTheme.typography.labelMedium,
                    color = MaterialTheme.colorScheme.onSurfaceVariant)
                Text("${token.amount} ${token.symbol}",
                    style = MaterialTheme.typography.labelMedium)
            }
            Text(token.usd, Modifier.padding(top = 8.dp),
                style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.Bold)
        }
    }
}