Jetpack Compose Components
Cuppa provides a comprehensive library of Jetpack Compose components that follow Material Design 3 guidelines while maintaining consistency across your application.
Component Library
Buttons
CuppaButton
A customizable button component with multiple variants:
import io.mycuppa.ui.components.*
@Composable
fun ButtonExamples() {
Column(
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
// Primary button
CuppaButton(
text = "Primary Action",
onClick = { handleAction() },
variant = ButtonVariant.Primary
)
// Secondary button
CuppaButton(
text = "Secondary Action",
onClick = { handleAction() },
variant = ButtonVariant.Secondary
)
// Outlined button
CuppaButton(
text = "Outlined",
onClick = { handleAction() },
variant = ButtonVariant.Outlined
)
// Text button
CuppaButton(
text = "Text Only",
onClick = { handleAction() },
variant = ButtonVariant.Text
)
// Loading state
CuppaButton(
text = "Submit",
onClick = { submit() },
isLoading = isSubmitting
)
// Disabled state
CuppaButton(
text = "Disabled",
onClick = { },
enabled = false
)
}
}
IconButton
Button with icon support:
CuppaIconButton(
icon = Icons.Default.Favorite,
onClick = { toggleFavorite() },
contentDescription = "Add to favorites"
)
Form Inputs
TextField
Text input with validation and styling:
@Composable
fun FormExample() {
var email by remember { mutableStateOf("") }
var name by remember { mutableStateOf("") }
var phone by remember { mutableStateOf("") }
Column(
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
CuppaTextField(
value = email,
onValueChange = { email = it },
label = "Email",
placeholder = "Enter your email",
keyboardType = KeyboardType.Email,
validation = ValidationRule.Email
)
CuppaTextField(
value = name,
onValueChange = { name = it },
label = "Full Name",
leadingIcon = Icons.Default.Person
)
CuppaTextField(
value = phone,
onValueChange = { phone = it },
label = "Phone",
keyboardType = KeyboardType.Phone
)
}
}
PasswordField
Password input with show/hide toggle:
var password by remember { mutableStateOf("") }
CuppaPasswordField(
value = password,
onValueChange = { password = it },
label = "Password",
placeholder = "Enter your password",
showToggle = true
)
TextArea
Multi-line text input:
var notes by remember { mutableStateOf("") }
CuppaTextArea(
value = notes,
onValueChange = { notes = it },
label = "Notes",
placeholder = "Enter your notes",
minLines = 3,
maxLines = 10
)
Lists and Collections
LazyColumn
Enhanced lazy column with built-in features:
@Composable
fun ItemListScreen(
items: List<Item>,
onItemClick: (Item) -> Unit
) {
CuppaLazyColumn(
items = items,
emptyState = {
CuppaEmptyState(
icon = Icons.Default.Inbox,
title = "No Items",
message = "Add your first item to get started"
)
}
) { item ->
CuppaListItem(
title = item.title,
subtitle = item.description,
onClick = { onItemClick(item) },
leading = {
Icon(Icons.Default.Circle, null)
},
trailing = {
Icon(Icons.Default.ChevronRight, null)
}
)
}
}
Grid
Responsive grid layout:
CuppaGrid(
items = products,
columns = 2,
spacing = 16.dp
) { product ->
ProductCard(product = product)
}
Cards
Card
Container with elevation and rounded corners:
CuppaCard(
modifier = Modifier.padding(16.dp),
elevation = 4.dp
) {
Column(
modifier = Modifier.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
Text(
text = "Card Title",
style = MaterialTheme.typography.titleMedium
)
Text(
text = "Card content goes here",
style = MaterialTheme.typography.bodyMedium
)
HorizontalDivider()
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
CuppaButton(
text = "Action",
onClick = { },
modifier = Modifier.weight(1f)
)
CuppaButton(
text = "Cancel",
onClick = { },
variant = ButtonVariant.Secondary,
modifier = Modifier.weight(1f)
)
}
}
}
Dialogs and Sheets
BottomSheet
Modal bottom sheet:
@Composable
fun ScreenWithBottomSheet() {
var showSheet by remember { mutableStateOf(false) }
Column {
CuppaButton(
text = "Show Sheet",
onClick = { showSheet = true }
)
}
if (showSheet) {
CuppaBottomSheet(
onDismiss = { showSheet = false }
) {
Column(
modifier = Modifier.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
Text(
text = "Bottom Sheet",
style = MaterialTheme.typography.titleLarge
)
Text("Content goes here")
CuppaButton(
text = "Close",
onClick = { showSheet = false }
)
}
}
}
}
Dialog
Alert dialog:
CuppaAlertDialog(
isOpen = showDialog,
onDismiss = { showDialog = false },
title = "Confirm Action",
message = "Are you sure you want to proceed?",
confirmButton = {
CuppaButton(
text = "Confirm",
onClick = {
confirmAction()
showDialog = false
}
)
},
dismissButton = {
CuppaButton(
text = "Cancel",
onClick = { showDialog = false },
variant = ButtonVariant.Text
)
}
)
Navigation
BottomNavigationBar
Bottom navigation with icons and labels:
@Composable
fun MainScreen() {
var selectedTab by remember { mutableStateOf(0) }
Scaffold(
bottomBar = {
CuppaBottomNavigationBar(
selectedIndex = selectedTab,
onTabSelected = { selectedTab = it },
tabs = listOf(
BottomNavTab(
label = "Home",
icon = Icons.Default.Home
),
BottomNavTab(
label = "Search",
icon = Icons.Default.Search
),
BottomNavTab(
label = "Profile",
icon = Icons.Default.Person
)
)
)
}
) { paddingValues ->
// Screen content
}
}
TopAppBar
Top app bar with navigation and actions:
CuppaTopAppBar(
title = "Screen Title",
navigationIcon = {
IconButton(onClick = { navigateBack() }) {
Icon(Icons.Default.ArrowBack, "Back")
}
},
actions = {
IconButton(onClick = { openSettings() }) {
Icon(Icons.Default.Settings, "Settings")
}
}
)
Indicators
LoadingSpinner
Activity indicator:
// Circular spinner
CuppaLoadingSpinner(
size = 48.dp,
color = MaterialTheme.colorScheme.primary
)
// Linear progress
CuppaLinearProgress(
progress = 0.7f,
modifier = Modifier.fillMaxWidth()
)
Snackbar
Temporary notification:
@Composable
fun ScreenWithSnackbar() {
val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()
Scaffold(
snackbarHost = { SnackbarHost(snackbarHostState) }
) { paddingValues ->
CuppaButton(
text = "Show Snackbar",
onClick = {
scope.launch {
snackbarHostState.showSnackbar(
message = "Action completed",
actionLabel = "Undo",
duration = SnackbarDuration.Short
)
}
}
)
}
}
Media
AsyncImage
Image loading with placeholders:
CuppaAsyncImage(
url = imageUrl,
contentDescription = "Product image",
placeholder = {
CircularProgressIndicator()
},
error = {
Icon(
Icons.Default.BrokenImage,
contentDescription = null
)
},
modifier = Modifier
.size(200.dp)
.clip(RoundedCornerShape(12.dp))
)
Theming
Apply custom themes:
@Composable
fun MyApp() {
CuppaTheme(
colorScheme = customColorScheme,
typography = customTypography,
shapes = customShapes
) {
// App content
}
}
val customColorScheme = lightColorScheme(
primary = Color(0xFF6200EE),
secondary = Color(0xFF03DAC6),
background = Color(0xFFFFFBFE)
)
Modifiers
Cuppa provides custom modifiers for common patterns:
// Card styling with shadow
myContent
.cuppaCard(
cornerRadius = 12.dp,
elevation = 4.dp
)
// Shimmer loading effect
myContent
.cuppaShimmer(isLoading = isLoading)
// Clickable with ripple
myContent
.cuppaClickable(
onClick = { },
rippleEnabled = true
)
Accessibility
All Cuppa components include built-in accessibility support:
CuppaButton(
text = "Submit",
onClick = { submit() },
modifier = Modifier.semantics {
contentDescription = "Submit form button"
role = Role.Button
}
)
Next Steps
- Explore the full Components Reference
- Learn about Theming and Customization
- See Android Examples