PinFlow is a lightweight, animated, and customizable OTP / PIN input library for Jetpack Compose. Built with Material 3, smart paste handling, secure PIN mode, and smooth interaction states — add polished verification flows in minutes.
Report a bug · Contributing · Security
- Features
- Preview
- Installation
- Quick start
- Usage examples
- API documentation
- Sample app
- Publishing & CI
- Contributing
- License
- Author
| Feature | Description |
|---|---|
| Single hidden field | One BasicTextField — reliable keyboard, paste, and a11y |
| Smart paste | Paste 123456 and all slots fill automatically |
| Modes | Boxes, Underline, Circle, SingleField, SecurePin |
| Motion | Bounce, Glow, ShakeOnError, Slide — pick per screen |
| Secure PIN | Masking + optional reveal-last-digit |
| Validation | PinFlowValidator helpers + onComplete callback |
| Material 3 | PinFlowDefaults.colors() / dimensions() |
| Boxes + smart paste | Underline + shake | Alphanumeric (6) |
|---|---|---|
![]() |
![]() |
![]() |
// settings.gradle.kts
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
}
}// build.gradle.kts
dependencies {
implementation("io.github.saadkhalidkhan:pinflow-compose:1.0.0")
}Available on Maven Central. See PUBLISHING.md for newer versions and RELEASE_CHECKLIST.md to ship releases.
Step 1. Add the JitPack repository in settings.gradle.kts (at the end of repositories):
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven { url = uri("https://jitpack.io") }
}
}Step 2. Add the dependency in build.gradle.kts:
dependencies {
implementation("com.github.saadkhalidkhan:PinFlow:1.0.0")
}Build status: green on JitPack for v1.0.0.
dependencies {
implementation(project(":pinflow"))
}import com.pinflow.compose.PinFlow
import com.pinflow.compose.PinFlowMode
import com.pinflow.compose.PinFlowValidator
var code by remember { mutableStateOf("") }
PinFlow(
value = code,
onValueChange = { code = it },
length = 6,
mode = PinFlowMode.Boxes,
isSuccess = PinFlowValidator.isComplete(code, 6),
onComplete = { submitted -> verifyOnServer(submitted) },
)PinFlow(
value = pin,
onValueChange = { pin = it },
mode = PinFlowMode.SecurePin,
revealLastDigit = true,
)val isError = code == "1234"
PinFlow(
value = code,
onValueChange = { code = it },
mode = PinFlowMode.Underline,
isError = isError,
animations = setOf(PinFlowAnimation.ShakeOnError, PinFlowAnimation.Bounce),
)PinFlow(
value = code,
onValueChange = { code = it },
isSuccess = PinFlowValidator.isComplete(code, 4) && code == "5678",
animations = setOf(PinFlowAnimation.Slide, PinFlowAnimation.Glow),
)PinFlow(
value = otp,
onValueChange = { otp = it },
colors = PinFlowDefaults.colors(),
dimensions = PinFlowDefaults.dimensions(
cellWidth = 52.dp,
spacing = 10.dp,
cornerRadius = 14.dp,
),
animations = setOf(PinFlowAnimation.Slide, PinFlowAnimation.Glow),
)PinFlow(
value = code,
onValueChange = { code = it },
length = 6,
mode = PinFlowMode.SingleField,
)PinFlowValidator.isComplete(otp, length = 6)
PinFlowValidator.isNumeric(otp)
PinFlowValidator.hasRepeatedDigits(otp)HTML API reference is generated with Dokka and published to GitHub Pages:
https://saadkhalidkhan.github.io/PinFlow/
Generate locally:
./gradlew :pinflow:dokkaGeneratePublicationHtml
# open pinflow/build/dokka/html/index.html./gradlew :sample:installDebugThe sample demonstrates all modes, secure PIN, success/slide, single-field, and alphanumeric input.
| Module | Description |
|---|---|
:pinflow |
Android library (minSdk 23) |
:sample |
Demo application |
| Workflow | Purpose |
|---|---|
| CI | Tests, assemble, Dokka on every push/PR |
| Docs | Deploy Dokka to GitHub Pages |
| Release | Publish to Maven Central on v* tags (or manual run) |
| Guide | Purpose |
|---|---|
| PUBLISHING.md | Maven Central + JitPack install & troubleshooting |
| RELEASE_CHECKLIST.md | Step-by-step for each new version |
| .github/SETUP_SECRETS.md | Optional GitHub Actions secrets for CI publish |
| .github/SETUP_PAGES.md | One-time GitHub Pages enablement for API docs |
| gradle.properties.example | Local credentials template (do not commit secrets) |
Contributions are welcome. Please read CONTRIBUTING.md and SECURITY.md before opening an issue or pull request.
- Open an issue to discuss larger changes.
- Fork the repo and create a branch from
master. - Run
./gradlew :pinflow:testDebugUnitTest :sample:assembleDebugbefore opening a PR. - Open a pull request with a clear description and media for UI changes.
This project is licensed under the Apache License 2.0 — see LICENSE.
Copyright 2026 Saad Khan
Saad Khan — GitHub · Medium · ranasaad0799@gmail.com
If this library helps you, consider starring the repo.



