Blocks
Memrizz Paywall
A subscription paywall with a Lite/Pro toggle, feature list, three selectable billing plans and a subscribe CTA.
Upgrade to
Memrizz Premium
LitePro
Everything in Memrizz Lite
Image Occlusion and Cloze decks
Process documents of up to 50 Mb
Generate cards in any language
Monthly
$14.99/ month
Semester
$44.97$42.00/ semester
Annual
$179.88$119.00/ year
Cancel anytime on the App Store
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 Plan(
val label: String,
val price: String,
val unit: String,
val originalPrice: String? = null,
)
@Composable
fun MemrizzPaywallScreen(
plans: List<Plan>,
selectedPlan: Int,
onSelectPlan: (Int) -> Unit,
onSubscribe: () -> Unit,
onDismiss: () -> Unit,
) {
val violet = Color(0xFF7C3AED)
Column(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.background)
.verticalScroll(rememberScrollState())
.padding(horizontal = 20.dp)
.padding(bottom = 24.dp),
) {
// Close
Box(Modifier.fillMaxWidth().padding(top = 16.dp)) {
IconButton(
onClick = onDismiss,
modifier = Modifier.align(Alignment.TopEnd).size(36.dp),
) {
Icon(Icons.Filled.Close, contentDescription = "Close")
}
}
// Headline
Text(
"Upgrade to",
style = MaterialTheme.typography.headlineSmall,
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f),
)
Text(
"Memrizz Premium",
style = MaterialTheme.typography.headlineSmall,
fontWeight = FontWeight.ExtraBold,
)
Spacer(Modifier.height(20.dp))
// Lite / Pro segmented toggle
Surface(
shape = CircleShape,
border = BorderStroke(1.dp, MaterialTheme.colorScheme.outline),
modifier = Modifier.fillMaxWidth(),
) {
Row(Modifier.padding(4.dp)) {
Text(
"Lite",
modifier = Modifier.weight(1f).padding(vertical = 8.dp),
textAlign = TextAlign.Center,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
Surface(
color = MaterialTheme.colorScheme.onBackground,
shape = CircleShape,
modifier = Modifier.weight(1f),
) {
Text(
"Pro",
modifier = Modifier.padding(vertical = 8.dp),
textAlign = TextAlign.Center,
style = MaterialTheme.typography.bodyMedium,
fontWeight = FontWeight.SemiBold,
color = MaterialTheme.colorScheme.background,
)
}
}
}
Spacer(Modifier.height(20.dp))
// Feature list
val features = listOf(
"Everything in Memrizz Lite",
"Image Occlusion and Cloze decks",
"Process documents of up to 50 Mb",
"Generate cards in any language",
)
features.forEach { feature ->
Row(
modifier = Modifier.padding(vertical = 6.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Surface(
shape = RoundedCornerShape(10.dp),
border = BorderStroke(1.dp, MaterialTheme.colorScheme.outline),
modifier = Modifier.size(36.dp),
) {
Box(contentAlignment = Alignment.Center) {
Icon(
Icons.Outlined.Star,
contentDescription = null,
modifier = Modifier.size(18.dp),
)
}
}
Spacer(Modifier.width(12.dp))
Text(feature, style = MaterialTheme.typography.bodyMedium)
}
}
Spacer(Modifier.height(16.dp))
// Plan cards
plans.forEachIndexed { i, plan ->
OutlinedCard(
onClick = { onSelectPlan(i) },
modifier = Modifier.fillMaxWidth().padding(bottom = 10.dp),
border = if (i == selectedPlan)
BorderStroke(1.5.dp, violet)
else
CardDefaults.outlinedCardBorder(),
colors = CardDefaults.outlinedCardColors(
containerColor = if (i == selectedPlan)
violet.copy(alpha = 0.06f)
else
MaterialTheme.colorScheme.surface,
),
) {
Row(
modifier = Modifier.fillMaxWidth().padding(14.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
) {
Text(
plan.label,
style = MaterialTheme.typography.bodyLarge,
fontWeight = FontWeight.SemiBold,
color = if (i == selectedPlan) violet
else MaterialTheme.colorScheme.onSurface,
)
Row(verticalAlignment = Alignment.Baseline) {
plan.originalPrice?.let {
Text(
it,
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant,
textDecoration = TextDecoration.LineThrough,
modifier = Modifier.padding(end = 4.dp),
)
}
Text(
plan.price,
style = MaterialTheme.typography.bodyLarge,
fontWeight = FontWeight.Bold,
)
Text(
" ${plan.unit}",
style = MaterialTheme.typography.labelSmall,
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
}
}
}
Text(
"Cancel anytime on the App Store",
modifier = Modifier.fillMaxWidth().padding(bottom = 12.dp),
textAlign = TextAlign.Center,
style = MaterialTheme.typography.labelSmall,
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
Button(
onClick = onSubscribe,
modifier = Modifier.fillMaxWidth(),
shape = CircleShape,
colors = ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.onBackground,
contentColor = MaterialTheme.colorScheme.background,
),
) {
Text("Subscribe", fontWeight = FontWeight.SemiBold)
}
}
}