Material Design components for Compose Multiplatform, specifically optimized for iOS devices running on ARM64 architecture
—
Material Design input components optimized for iOS touch interactions, keyboard behavior, and accessibility standards.
Material text input field with iOS-optimized keyboard behavior and native integration.
/**
* Material Design filled text field with iOS keyboard integration
* Text fields allow users to enter and edit text
* @param value The input text to be shown in the text field
* @param onValueChange Called when the input service updates the text
* @param modifier Modifier to be applied to this text field
* @param enabled Controls the enabled state of this text field
* @param readOnly Controls the editable state of the text field
* @param textStyle The style to be applied to the input text
* @param label The optional label to be displayed inside the text field container
* @param placeholder The optional placeholder to be displayed when the text field is in focus and the input text is empty
* @param leadingIcon The optional leading icon to be displayed at the beginning of the text field container
* @param trailingIcon The optional trailing icon to be displayed at the end of the text field container
* @param isError Indicates if the text field's current value is in error state
* @param visualTransformation Transforms the visual representation of the input value
* @param keyboardOptions Software keyboard options that contains configuration such as KeyboardType and ImeAction
* @param keyboardActions When the input service emits an IME action, the corresponding callback is called
* @param singleLine When set to true, this text field becomes a single horizontally scrolling text field
* @param maxLines The maximum number of visible lines
* @param colors TextFieldColors that will be used to resolve the colors used for this text field
*/
@Composable
fun TextField(
value: String,
onValueChange: (String) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
readOnly: Boolean = false,
textStyle: TextStyle = LocalTextStyle.current,
label: @Composable (() -> Unit)? = null,
placeholder: @Composable (() -> Unit)? = null,
leadingIcon: @Composable (() -> Unit)? = null,
trailingIcon: @Composable (() -> Unit)? = null,
isError: Boolean = false,
visualTransformation: VisualTransformation = VisualTransformation.None,
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
keyboardActions: KeyboardActions = KeyboardActions.Default,
singleLine: Boolean = false,
maxLines: Int = Int.MAX_VALUE,
colors: TextFieldColors = TextFieldDefaults.textFieldColors()
)Usage Examples:
// Basic text field
var text by remember { mutableStateOf("") }
TextField(
value = text,
onValueChange = { text = it },
label = { Text("Enter text") }
)
// Password field with iOS-style visibility toggle
var password by remember { mutableStateOf("") }
var passwordVisible by remember { mutableStateOf(false) }
TextField(
value = password,
onValueChange = { password = it },
label = { Text("Password") },
visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(),
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
trailingIcon = {
val image = if (passwordVisible) Icons.Filled.Visibility else Icons.Filled.VisibilityOff
IconButton(onClick = { passwordVisible = !passwordVisible }) {
Icon(imageVector = image, contentDescription = null)
}
}
)
// Email field with iOS keyboard optimization
var email by remember { mutableStateOf("") }
TextField(
value = email,
onValueChange = { email = it },
label = { Text("Email") },
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Email,
imeAction = ImeAction.Next
),
leadingIcon = {
Icon(Icons.Default.Email, contentDescription = null)
}
)
// Multi-line text field with iOS-style scrolling
var multilineText by remember { mutableStateOf("") }
TextField(
value = multilineText,
onValueChange = { multilineText = it },
label = { Text("Description") },
maxLines = 5,
modifier = Modifier.fillMaxWidth()
)Text field with outlined border styling, following Material Design with iOS visual adaptations.
/**
* Material Design outlined text field with iOS-optimized border styling
* @param value The input text to be shown in the text field
* @param onValueChange Called when the input service updates the text
* @param modifier Modifier to be applied to this text field
* @param enabled Controls the enabled state of this text field
* @param readOnly Controls the editable state of the text field
* @param textStyle The style to be applied to the input text
* @param label The optional label to be displayed inside the text field container
* @param placeholder The optional placeholder to be displayed when the text field is in focus and the input text is empty
* @param leadingIcon The optional leading icon to be displayed at the beginning of the text field container
* @param trailingIcon The optional trailing icon to be displayed at the end of the text field container
* @param isError Indicates if the text field's current value is in error state
* @param visualTransformation Transforms the visual representation of the input value
* @param keyboardOptions Software keyboard options that contains configuration such as KeyboardType and ImeAction
* @param keyboardActions When the input service emits an IME action, the corresponding callback is called
* @param singleLine When set to true, this text field becomes a single horizontally scrolling text field
* @param maxLines The maximum number of visible lines
* @param colors TextFieldColors that will be used to resolve the colors used for this text field
*/
@Composable
fun OutlinedTextField(
value: String,
onValueChange: (String) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
readOnly: Boolean = false,
textStyle: TextStyle = LocalTextStyle.current,
label: @Composable (() -> Unit)? = null,
placeholder: @Composable (() -> Unit)? = null,
leadingIcon: @Composable (() -> Unit)? = null,
trailingIcon: @Composable (() -> Unit)? = null,
isError: Boolean = false,
visualTransformation: VisualTransformation = VisualTransformation.None,
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
keyboardActions: KeyboardActions = KeyboardActions.Default,
singleLine: Boolean = false,
maxLines: Int = Int.MAX_VALUE,
colors: TextFieldColors = TextFieldDefaults.outlinedTextFieldColors()
)Material checkbox for boolean selection with iOS-style animation and accessibility.
/**
* Material Design checkbox with iOS-optimized touch targets and animations
* @param checked Whether this checkbox is checked or unchecked
* @param onCheckedChange Called when this checkbox is clicked
* @param modifier Modifier to be applied to this checkbox
* @param enabled Controls the enabled state of this checkbox
* @param colors CheckboxColors that will be used to resolve the colors used for this checkbox
*/
@Composable
fun Checkbox(
checked: Boolean,
onCheckedChange: ((Boolean) -> Unit)?,
modifier: Modifier = Modifier,
enabled: Boolean = true,
colors: CheckboxColors = CheckboxDefaults.colors()
)Usage Examples:
// Basic checkbox
var isChecked by remember { mutableStateOf(false) }
Checkbox(
checked = isChecked,
onCheckedChange = { isChecked = it }
)
// Checkbox with label (iOS-style)
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.clickable { isChecked = !isChecked }
.padding(16.dp)
) {
Checkbox(
checked = isChecked,
onCheckedChange = { isChecked = it }
)
Spacer(modifier = Modifier.width(8.dp))
Text("Enable notifications")
}
// Custom colored checkbox
Checkbox(
checked = isChecked,
onCheckedChange = { isChecked = it },
colors = CheckboxDefaults.colors(
checkedColor = MaterialTheme.colors.secondary
)
)Single selection radio button with iOS-style visual feedback.
/**
* Material Design radio button with iOS-optimized selection states
* @param selected Whether this radio button is selected or unselected
* @param onClick Called when this radio button is clicked
* @param modifier Modifier to be applied to this radio button
* @param enabled Controls the enabled state of this radio button
* @param colors RadioButtonColors that will be used to resolve the colors used for this radio button
*/
@Composable
fun RadioButton(
selected: Boolean,
onClick: (() -> Unit)?,
modifier: Modifier = Modifier,
enabled: Boolean = true,
colors: RadioButtonColors = RadioButtonDefaults.colors()
)Usage Examples:
// Radio button group
val options = listOf("Option 1", "Option 2", "Option 3")
var selectedOption by remember { mutableStateOf(options[0]) }
Column {
options.forEach { option ->
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.clickable { selectedOption = option }
.padding(horizontal = 16.dp, vertical = 8.dp)
) {
RadioButton(
selected = (option == selectedOption),
onClick = { selectedOption = option }
)
Spacer(modifier = Modifier.width(8.dp))
Text(text = option)
}
}
}Toggle switch component with iOS-style animations and haptic feedback integration.
/**
* Material Design switch with iOS-style toggle animations
* @param checked Whether or not this switch is checked
* @param onCheckedChange Called when this switch is clicked
* @param modifier Modifier to be applied to this switch
* @param enabled Controls the enabled state of this switch
* @param colors SwitchColors that will be used to resolve the colors used for this switch
*/
@Composable
fun Switch(
checked: Boolean,
onCheckedChange: ((Boolean) -> Unit)?,
modifier: Modifier = Modifier,
enabled: Boolean = true,
colors: SwitchColors = SwitchDefaults.colors()
)Usage Examples:
// Basic switch
var isSwitchOn by remember { mutableStateOf(false) }
Switch(
checked = isSwitchOn,
onCheckedChange = { isSwitchOn = it }
)
// Switch with label (iOS settings style)
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Text("Dark Mode")
Switch(
checked = isSwitchOn,
onCheckedChange = { isSwitchOn = it }
)
}
// Custom styled switch
Switch(
checked = isSwitchOn,
onCheckedChange = { isSwitchOn = it },
colors = SwitchDefaults.colors(
checkedThumbColor = MaterialTheme.colors.secondary,
checkedTrackColor = MaterialTheme.colors.secondary.copy(alpha = 0.5f)
)
)Value selection slider with iOS-style thumb and track styling.
/**
* Material Design slider with iOS-optimized touch handling
* @param value Current value of the slider
* @param onValueChange Called when the value changes
* @param modifier Modifier to be applied to this slider
* @param enabled Controls the enabled state of this slider
* @param valueRange The range of values that this slider can take
* @param steps If greater than 0, specifies the amount of discrete allowable values
* @param onValueChangeFinished Called when value change has ended with a final value
* @param colors SliderColors that will be used to resolve the colors used for this slider
*/
@Composable
fun Slider(
value: Float,
onValueChange: (Float) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
valueRange: ClosedFloatingPointRange<Float> = 0f..1f,
steps: Int = 0,
onValueChangeFinished: (() -> Unit)? = null,
colors: SliderColors = SliderDefaults.colors()
)Usage Examples:
// Basic slider
var sliderValue by remember { mutableStateOf(0.5f) }
Slider(
value = sliderValue,
onValueChange = { sliderValue = it }
)
// Volume slider with icons (iOS style)
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
verticalAlignment = Alignment.CenterVertically
) {
Icon(Icons.Default.VolumeDown, contentDescription = null)
Slider(
value = sliderValue,
onValueChange = { sliderValue = it },
modifier = Modifier.weight(1f),
colors = SliderDefaults.colors(
thumbColor = MaterialTheme.colors.primary,
activeTrackColor = MaterialTheme.colors.primary
)
)
Icon(Icons.Default.VolumeUp, contentDescription = null)
}
// Range slider with steps
var rangeSliderValue by remember { mutableStateOf(0.2f..0.8f) }
RangeSlider(
value = rangeSliderValue,
onValueChange = { rangeSliderValue = it },
valueRange = 0f..1f,
steps = 10
)object TextFieldDefaults {
fun textFieldColors(
textColor: Color = MaterialTheme.colors.onSurface,
disabledTextColor: Color = MaterialTheme.colors.onSurface.copy(alpha = ContentAlpha.disabled),
backgroundColor: Color = MaterialTheme.colors.onSurface.copy(alpha = 0.12f),
cursorColor: Color = MaterialTheme.colors.primary,
errorCursorColor: Color = MaterialTheme.colors.error,
focusedIndicatorColor: Color = MaterialTheme.colors.primary.copy(alpha = ContentAlpha.high),
unfocusedIndicatorColor: Color = MaterialTheme.colors.onSurface.copy(alpha = ContentAlpha.medium),
disabledIndicatorColor: Color = unfocusedIndicatorColor.copy(alpha = ContentAlpha.disabled),
errorIndicatorColor: Color = MaterialTheme.colors.error,
leadingIconColor: Color = MaterialTheme.colors.onSurface.copy(alpha = IconOpacity),
disabledLeadingIconColor: Color = leadingIconColor.copy(alpha = ContentAlpha.disabled),
errorLeadingIconColor: Color = leadingIconColor,
trailingIconColor: Color = MaterialTheme.colors.onSurface.copy(alpha = IconOpacity),
disabledTrailingIconColor: Color = trailingIconColor.copy(alpha = ContentAlpha.disabled),
errorTrailingIconColor: Color = MaterialTheme.colors.error,
focusedLabelColor: Color = MaterialTheme.colors.primary.copy(alpha = ContentAlpha.high),
unfocusedLabelColor: Color = MaterialTheme.colors.onSurface.copy(alpha = ContentAlpha.medium),
disabledLabelColor: Color = unfocusedLabelColor.copy(alpha = ContentAlpha.disabled),
errorLabelColor: Color = MaterialTheme.colors.error,
placeholderColor: Color = MaterialTheme.colors.onSurface.copy(alpha = ContentAlpha.medium),
disabledPlaceholderColor: Color = placeholderColor.copy(alpha = ContentAlpha.disabled)
): TextFieldColors
fun outlinedTextFieldColors(/* similar parameters */): TextFieldColors
}
object CheckboxDefaults {
fun colors(
checkedColor: Color = MaterialTheme.colors.secondary,
uncheckedColor: Color = MaterialTheme.colors.onSurface.copy(alpha = 0.6f),
checkmarkColor: Color = MaterialTheme.colors.surface,
disabledColor: Color = MaterialTheme.colors.onSurface.copy(alpha = ContentAlpha.disabled),
disabledIndeterminateColor: Color = checkedColor.copy(alpha = ContentAlpha.disabled)
): CheckboxColors
}
object RadioButtonDefaults {
fun colors(
selectedColor: Color = MaterialTheme.colors.secondary,
unselectedColor: Color = MaterialTheme.colors.onSurface.copy(alpha = 0.6f),
disabledColor: Color = MaterialTheme.colors.onSurface.copy(alpha = ContentAlpha.disabled)
): RadioButtonColors
}
object SwitchDefaults {
fun colors(
checkedThumbColor: Color = MaterialTheme.colors.secondaryVariant,
checkedTrackColor: Color = checkedThumbColor,
checkedTrackAlpha: Float = 0.54f,
uncheckedThumbColor: Color = MaterialTheme.colors.surface,
uncheckedTrackColor: Color = MaterialTheme.colors.onSurface,
uncheckedTrackAlpha: Float = 0.38f,
disabledCheckedThumbColor: Color = MaterialTheme.colors.surface,
disabledCheckedTrackColor: Color = MaterialTheme.colors.onSurface,
disabledUncheckedThumbColor: Color = disabledCheckedThumbColor,
disabledUncheckedTrackColor: Color = disabledCheckedTrackColor
): SwitchColors
}
object SliderDefaults {
fun colors(
thumbColor: Color = MaterialTheme.colors.primary,
disabledThumbColor: Color = MaterialTheme.colors.onSurface.copy(alpha = ContentAlpha.disabled),
activeTrackColor: Color = MaterialTheme.colors.primary,
inactiveTrackColor: Color = activeTrackColor.copy(alpha = 0.24f),
disabledActiveTrackColor: Color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f),
disabledInactiveTrackColor: Color = disabledActiveTrackColor.copy(alpha = 0.12f),
activeTickColor: Color = contentColorFor(activeTrackColor).copy(alpha = 0.54f),
inactiveTickColor: Color = activeTrackColor.copy(alpha = 0.54f),
disabledActiveTickColor: Color = activeTickColor.copy(alpha = ContentAlpha.disabled),
disabledInactiveTickColor: Color = disabledActiveTrackColor.copy(alpha = ContentAlpha.disabled)
): SliderColors
}
// Visual transformation for password fields
class PasswordVisualTransformation(val mask: Char = '\u2022') : VisualTransformation
// Keyboard options for iOS optimization
data class KeyboardOptions(
val capitalization: KeyboardCapitalization = KeyboardCapitalization.None,
val autoCorrect: Boolean = true,
val keyboardType: KeyboardType = KeyboardType.Text,
val imeAction: ImeAction = ImeAction.Default
)
enum class KeyboardType {
Text, Ascii, Number, Phone, Uri, Email, Password, NumberPassword
}
enum class ImeAction {
Default, None, Go, Search, Send, Previous, Next, Done
}Material dropdown menu for displaying a list of selectable options with iOS-optimized positioning and animations.
/**
* Material Design dropdown menu with iOS-optimized presentation
* @param expanded Whether the dropdown menu is currently expanded and visible
* @param onDismissRequest Called when the user requests to dismiss the menu
* @param modifier Modifier to be applied to this dropdown menu
* @param offset DpOffset to be added to the position of the menu
* @param properties PopupProperties for further customization
* @param content The content of this dropdown menu, typically DropdownMenuItems
*/
@Composable
fun DropdownMenu(
expanded: Boolean,
onDismissRequest: () -> Unit,
modifier: Modifier = Modifier,
offset: DpOffset = DpOffset.Zero,
properties: PopupProperties = PopupProperties(focusable = true),
content: @Composable ColumnScope.() -> Unit
)
/**
* Material Design dropdown menu item with click handling and iOS touch feedback
* @param onClick Called when this menu item is clicked
* @param modifier Modifier to be applied to this menu item
* @param enabled Whether this menu item is enabled for selection
* @param contentPadding The spacing values to apply internally between the container and the content
* @param interactionSource The MutableInteractionSource representing the stream of interactions
* @param content The content to be displayed inside this menu item
*/
@Composable
fun DropdownMenuItem(
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
contentPadding: PaddingValues = MenuDefaults.DropdownMenuItemContentPadding,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: @Composable RowScope.() -> Unit
)
@Immutable
data class DpOffset(val x: Dp, val y: Dp) {
companion object {
val Zero = DpOffset(0.dp, 0.dp)
}
}
data class PopupProperties(
val focusable: Boolean = true,
val dismissOnBackPress: Boolean = true,
val dismissOnClickOutside: Boolean = true,
val securePolicy: SecureFlagPolicy = SecureFlagPolicy.Inherit,
val excludeFromSystemGesture: Boolean = true,
val clippingEnabled: Boolean = true
)
object MenuDefaults {
val DropdownMenuItemContentPadding: PaddingValues =
PaddingValues(horizontal = 16.dp, vertical = 12.dp)
}Usage Examples:
// Basic dropdown menu
var expanded by remember { mutableStateOf(false) }
var selectedOption by remember { mutableStateOf("Select Option") }
val options = listOf("Option 1", "Option 2", "Option 3")
Box {
Button(
onClick = { expanded = true }
) {
Text(selectedOption)
Icon(
imageVector = Icons.Default.ArrowDropDown,
contentDescription = null
)
}
DropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false }
) {
options.forEach { option ->
DropdownMenuItem(
onClick = {
selectedOption = option
expanded = false
}
) {
Text(option)
}
}
}
}
// Dropdown menu with icons and dividers
DropdownMenu(
expanded = menuExpanded,
onDismissRequest = { menuExpanded = false }
) {
DropdownMenuItem(
onClick = {
// Handle edit action
menuExpanded = false
}
) {
Icon(
imageVector = Icons.Default.Edit,
contentDescription = null,
modifier = Modifier.size(18.dp)
)
Spacer(modifier = Modifier.width(8.dp))
Text("Edit")
}
DropdownMenuItem(
onClick = {
// Handle share action
menuExpanded = false
}
) {
Icon(
imageVector = Icons.Default.Share,
contentDescription = null,
modifier = Modifier.size(18.dp)
)
Spacer(modifier = Modifier.width(8.dp))
Text("Share")
}
Divider()
DropdownMenuItem(
onClick = {
// Handle delete action
menuExpanded = false
}
) {
Icon(
imageVector = Icons.Default.Delete,
contentDescription = null,
modifier = Modifier.size(18.dp),
tint = MaterialTheme.colors.error
)
Spacer(modifier = Modifier.width(8.dp))
Text(
text = "Delete",
color = MaterialTheme.colors.error
)
}
}Install with Tessl CLI
npx tessl i tessl/maven-org-jetbrains-compose-material--material-uikitarm64