
Highly customizable digital signature library enables drawing with features like undo/redo, grid display, fullscreen mode, real-time updates, state management, and multiple export options.
A customizable Compose Multiplatform library for capturing digital signatures. The library provides comprehensive state management, undo/redo functionality, and support for Android, iOS, Desktop ( JVM), and Web (JS/WASM) platforms.
Add the dependency to your build.gradle.kts:
dependencies {
implementation("io.github.niyajali:compose-signature:1.0.2")
}@Composable
fun SimpleSignature() {
var signature by remember { mutableStateOf<ImageBitmap?>(null) }
ComposeSign(
onSignatureUpdate = { signature = it },
modifier = Modifier
.fillMaxWidth()
.height(200.dp)
)
}@Composable
fun AdvancedSignature() {
val signatureState = rememberSignatureState()
var signature by remember { mutableStateOf<ImageBitmap?>(null) }
ComposeSign(
onSignatureUpdate = { signature = it },
config = SignatureConfig(
strokeColor = Color.Blue,
strokeWidth = 4.dp,
backgroundColor = Color.White,
showGrid = true,
gridColor = Color.Gray.copy(alpha = 0.3f),
showActions = true,
borderStroke = BorderStroke(2.dp, Color.Gray),
cornerShape = RoundedCornerShape(12.dp)
),
state = signatureState,
onActionClicked = { action ->
when (action) {
SignatureAction.CLEAR -> signatureState.clear()
SignatureAction.UNDO -> signatureState.undo()
SignatureAction.REDO -> signatureState.redo()
SignatureAction.SAVE -> {
signature?.let { /* Save to file */ }
}
}
}
)
}The main composable provides multiple overloads for different levels of customization:
// Simple usage
ComposeSign(onSignatureUpdate = { signature = it })
// Basic customization
ComposeSign(
onSignatureUpdate = { signature = it },
strokeColor = Color.Blue,
strokeWidth = 4.dp,
showGrid = true
)
// Full configuration
ComposeSign(
onSignatureUpdate = { signature = it },
config = SignatureConfig(/* ... */),
state = rememberSignatureState(),
onActionClicked = { action -> /* handle action */ }
)Configuration object for controlling visual appearance and behavior:
data class SignatureConfig(
val strokeColor: Color = Color.Black,
val strokeWidth: Dp = 3.dp,
val backgroundColor: Color = Color.White,
val borderStroke: BorderStroke? = BorderStroke(1.dp, Color.Gray),
val cornerShape: CornerBasedShape = RoundedCornerShape(8.dp),
val showGrid: Boolean = false,
val gridColor: Color = Color.Gray.copy(alpha = 0.3f),
val gridSpacing: Dp = 20.dp,
val isFullScreen: Boolean = false,
val minHeight: Dp = 200.dp,
val maxHeight: Dp = 400.dp,
val showActions: Boolean = false,
val enableSmoothDrawing: Boolean = true
)Predefined configurations are available:
SignatureConfig.Default - Standard configurationSignatureConfig.Fullscreen - Fullscreen mode with actionsSignatureConfig.WithGrid - Includes grid overlaySignatureConfig.ThickStroke - Thicker stroke widthSignatureConfig.Professional - Professional document stylingSignatureConfig.Creative - Creative color schemeSignatureConfig.FormIntegration - Compact form stylingManages signature paths, input state, and history:
val state = rememberSignatureState()
// Available properties
state.paths // List of signature paths
state.inputState // Current input state (IDLE, DRAWING, COMPLETED)
state.signature // Generated ImageBitmap
state.canUndo // Whether undo is available
state.canRedo // Whether redo is available
// Operations
state.addPath(path)
state.clear()
state.undo()
state.redo()
// Extension functions
state.isEmpty()
state.getSignatureBounds()
state.getMetadata()
state.exportSignature(width, height)
state.isValid()@Composable
fun FullscreenExample() {
var showFullscreen by remember { mutableStateOf(false) }
var signature by remember { mutableStateOf<ImageBitmap?>(null) }
if (showFullscreen) {
ComposeSignFullscreen(
onSignatureUpdate = { signature = it },
onDismiss = { showFullscreen = false },
config = SignatureConfig.Fullscreen
)
}
}// Dark theme
ComposeSign(config = SignatureConfig.Default.asDarkTheme())
// High contrast for accessibility
ComposeSign(config = SignatureConfig.Default.asAccessible(highContrast = true))
// Form integration
ComposeSign(config = SignatureConfig.FormIntegration)@Composable
fun MultiColorSignature() {
var currentColor by remember { mutableStateOf(Color.Black) }
ComposeSign(
onSignatureUpdate = { signature = it },
strokeColor = currentColor,
strokeWidth = 4.dp,
showGrid = true
)
ColorPicker(
selectedColor = currentColor,
onColorSelected = { currentColor = it }
)
}val state = rememberSignatureState()
val metadata = state.getMetadata()
println("Path count: ${metadata.pathCount}")
println("Complexity: ${metadata.complexityDescription()}")
println("Total length: ${metadata.totalLength}")
val bounds = state.getSignatureBounds()
bounds?.let {
println("Dimensions: ${it.width} x ${it.height}")
println("Area: ${it.area()}")
}val isValid = state.isValid(
minPaths = 5,
minLength = 100f,
minComplexity = 20
)The library follows SOLID principles with clear separation of concerns:
Copyright 2026 Niyaj Ali
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
A customizable Compose Multiplatform library for capturing digital signatures. The library provides comprehensive state management, undo/redo functionality, and support for Android, iOS, Desktop ( JVM), and Web (JS/WASM) platforms.
Add the dependency to your build.gradle.kts:
dependencies {
implementation("io.github.niyajali:compose-signature:1.0.2")
}@Composable
fun SimpleSignature() {
var signature by remember { mutableStateOf<ImageBitmap?>(null) }
ComposeSign(
onSignatureUpdate = { signature = it },
modifier = Modifier
.fillMaxWidth()
.height(200.dp)
)
}@Composable
fun AdvancedSignature() {
val signatureState = rememberSignatureState()
var signature by remember { mutableStateOf<ImageBitmap?>(null) }
ComposeSign(
onSignatureUpdate = { signature = it },
config = SignatureConfig(
strokeColor = Color.Blue,
strokeWidth = 4.dp,
backgroundColor = Color.White,
showGrid = true,
gridColor = Color.Gray.copy(alpha = 0.3f),
showActions = true,
borderStroke = BorderStroke(2.dp, Color.Gray),
cornerShape = RoundedCornerShape(12.dp)
),
state = signatureState,
onActionClicked = { action ->
when (action) {
SignatureAction.CLEAR -> signatureState.clear()
SignatureAction.UNDO -> signatureState.undo()
SignatureAction.REDO -> signatureState.redo()
SignatureAction.SAVE -> {
signature?.let { /* Save to file */ }
}
}
}
)
}The main composable provides multiple overloads for different levels of customization:
// Simple usage
ComposeSign(onSignatureUpdate = { signature = it })
// Basic customization
ComposeSign(
onSignatureUpdate = { signature = it },
strokeColor = Color.Blue,
strokeWidth = 4.dp,
showGrid = true
)
// Full configuration
ComposeSign(
onSignatureUpdate = { signature = it },
config = SignatureConfig(/* ... */),
state = rememberSignatureState(),
onActionClicked = { action -> /* handle action */ }
)Configuration object for controlling visual appearance and behavior:
data class SignatureConfig(
val strokeColor: Color = Color.Black,
val strokeWidth: Dp = 3.dp,
val backgroundColor: Color = Color.White,
val borderStroke: BorderStroke? = BorderStroke(1.dp, Color.Gray),
val cornerShape: CornerBasedShape = RoundedCornerShape(8.dp),
val showGrid: Boolean = false,
val gridColor: Color = Color.Gray.copy(alpha = 0.3f),
val gridSpacing: Dp = 20.dp,
val isFullScreen: Boolean = false,
val minHeight: Dp = 200.dp,
val maxHeight: Dp = 400.dp,
val showActions: Boolean = false,
val enableSmoothDrawing: Boolean = true
)Predefined configurations are available:
SignatureConfig.Default - Standard configurationSignatureConfig.Fullscreen - Fullscreen mode with actionsSignatureConfig.WithGrid - Includes grid overlaySignatureConfig.ThickStroke - Thicker stroke widthSignatureConfig.Professional - Professional document stylingSignatureConfig.Creative - Creative color schemeSignatureConfig.FormIntegration - Compact form stylingManages signature paths, input state, and history:
val state = rememberSignatureState()
// Available properties
state.paths // List of signature paths
state.inputState // Current input state (IDLE, DRAWING, COMPLETED)
state.signature // Generated ImageBitmap
state.canUndo // Whether undo is available
state.canRedo // Whether redo is available
// Operations
state.addPath(path)
state.clear()
state.undo()
state.redo()
// Extension functions
state.isEmpty()
state.getSignatureBounds()
state.getMetadata()
state.exportSignature(width, height)
state.isValid()@Composable
fun FullscreenExample() {
var showFullscreen by remember { mutableStateOf(false) }
var signature by remember { mutableStateOf<ImageBitmap?>(null) }
if (showFullscreen) {
ComposeSignFullscreen(
onSignatureUpdate = { signature = it },
onDismiss = { showFullscreen = false },
config = SignatureConfig.Fullscreen
)
}
}// Dark theme
ComposeSign(config = SignatureConfig.Default.asDarkTheme())
// High contrast for accessibility
ComposeSign(config = SignatureConfig.Default.asAccessible(highContrast = true))
// Form integration
ComposeSign(config = SignatureConfig.FormIntegration)@Composable
fun MultiColorSignature() {
var currentColor by remember { mutableStateOf(Color.Black) }
ComposeSign(
onSignatureUpdate = { signature = it },
strokeColor = currentColor,
strokeWidth = 4.dp,
showGrid = true
)
ColorPicker(
selectedColor = currentColor,
onColorSelected = { currentColor = it }
)
}val state = rememberSignatureState()
val metadata = state.getMetadata()
println("Path count: ${metadata.pathCount}")
println("Complexity: ${metadata.complexityDescription()}")
println("Total length: ${metadata.totalLength}")
val bounds = state.getSignatureBounds()
bounds?.let {
println("Dimensions: ${it.width} x ${it.height}")
println("Area: ${it.area()}")
}val isValid = state.isValid(
minPaths = 5,
minLength = 100f,
minComplexity = 20
)The library follows SOLID principles with clear separation of concerns:
Copyright 2026 Niyaj Ali
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.