CMP OTP PinView is a Kotlin Multiplatform library that provides highly customizable OTP/PIN input fields for Android and iOS. Built with Compose Multiplatform, it allows developers to create secure and visually appealing OTP input experiences which is completely customizable.
- Multi-Platform OTP Components – Reusable OTP input fields for Android, iOS, and Web.
- Customizable Styles – Control colors, borders, spacing, corner radius, and shapes.
- Obscure / Visibility Toggle – Show or hide entered PIN digits dynamically.
- Reactive Focus Handling – Automatically focuses next input and hides keyboard when complete.
- Android OTP Autofill – Automatically observes system OTPs for Android.
Add the library to your project:
dependencies {
implementation("network.chaintech.cmp-otp-pin-view:1.0.0")
}Make sure to include Maven Central in your repositories:
repositories {
mavenCentral()
}@Composable
fun BasicOTPExample() {
var hasError by remember { mutableStateOf(false) }
OTPField(
otpLength = 4,
stylePreset = OtpFieldStylePreset.Normal,
isError = hasError,
isObserveAndroidOTP = true,
instanceKey = "normal",
obscureField = true
)
}| Property | Type | Default | Description |
|---|---|---|---|
otpLength |
Int |
4 | Number of OTP/PIN input fields to display. |
instanceKey |
String? |
null | Unique key for this OTPField instance (used internally for state handling). |
stylePreset |
OtpFieldStylePreset? |
null | Predefined style preset (shape, colors, borders, spacing). |
borderColorFocused |
Color |
Color.Blue |
Border color when the field is focused. |
borderColorUnfocused |
Color |
Color.Gray |
Border color when the field is not focused. |
borderWidth |
Dp |
1.dp | Width of the field border. |
backgroundColorFocused |
Color |
Color.White |
Background color when focused. |
backgroundColorUnFocused |
Color |
Color.White |
Background color when not focused. |
textColor |
Color |
Color.Blue |
Color of the entered digits. |
cursorColor |
Color |
Color.Blue |
Cursor color. |
cornerRadius |
Dp |
12.dp | Corner radius for rounded shapes. |
shape |
Shape |
RoundedCornerShape(cornerRadius) |
Custom shape for input fields. |
obscureField |
Boolean |
false | Hide the entered PIN; shows a toggle eye icon if true. |
isError |
Boolean |
false | Marks the field as error for styling. |
isObserveAndroidOTP |
Boolean |
false | Observes system OTP autofill on Android. |
OTPField(otpLength = 5, stylePreset = OtpFieldStylePreset.Normal)
OTPField(otpLength = 5, stylePreset = OtpFieldStylePreset.Circle)
OTPField(otpLength = 5, stylePreset = OtpFieldStylePreset.Hexagon)
OTPField(otpLength = 5, stylePreset = OtpFieldStylePreset.Heart)
OTPField(otpLength = 5, stylePreset = OtpFieldStylePreset.Triangle)
OTPField(otpLength = 5, stylePreset = OtpFieldStylePreset.Pentagon)
OTPField(otpLength = 5, stylePreset = OtpFieldStylePreset.FilledParallelogram)val customShape = RoundedCornerShape(topStart = 16.dp, bottomEnd = 16.dp)
OTPField(
otpLength = 4,
stylePreset = OtpFieldStylePreset.Normal.copy(shape = customShape),
instanceKey = "custom"
)var isError by remember { mutableStateOf(false) }
val enteredOtp = remember { mutableStateOf("") }
OTPField(
otpLength = 6,
stylePreset = OtpFieldStylePreset.Hexagon,
isError = isError,
instanceKey = "hexagon"
)
Button(onClick = {
isError = enteredOtp.value != "123456" // Example validation
}) {
Text("Validate OTP")
}OTPField(
otpLength = 4,
obscureField = true,
instanceKey = "obscure"
)The field will display a toggle icon to show or hide PIN digits.
Set isObserveAndroidOTP = true to automatically observe system OTPs (SMS Retriever) and populate the fields.
- Rounded Rectangle
- Circle
- Hexagon
- Heart
- Triangle
- Pentagon
- Parallelogram
@Composable
fun OTPPreview() {
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
Text("Normal")
OTPField(otpLength = 4, stylePreset = OtpFieldStylePreset.Normal, instanceKey = "normal")
Text("Circle")
OTPField(otpLength = 4, stylePreset = OtpFieldStylePreset.Circle, instanceKey = "circle")
Text("Hexagon")
OTPField(otpLength = 4, stylePreset = OtpFieldStylePreset.Hexagon, instanceKey = "hex")
Text("Heart")
OTPField(otpLength = 4, stylePreset = OtpFieldStylePreset.Heart, instanceKey = "heart")
Text("Triangle")
OTPField(otpLength = 4, stylePreset = OtpFieldStylePreset.Triangle, instanceKey = "triangle")
Text("Pentagon")
OTPField(otpLength = 4, stylePreset = OtpFieldStylePreset.Pentagon, instanceKey = "pentagon")
Text("Filled Parallelogram")
OTPField(otpLength = 4, stylePreset = OtpFieldStylePreset.FilledParallelogram, instanceKey = "parallelogram")
}
}

