Overview¶
KForm is a Kotlin open source library that simplifies the development of demanding forms.
KForm leverages Kotlin Multiplatform to allow developers to define the structure and validations of a form in code that can be shared with both server and client applications.
For documentation on how to use KForm, please follow the user guide:
Features¶
- Define the schema and validations of your form in common (i.e. shared) Kotlin code, where:
- Schemas and validations may be defined over tabular data and/or any other type of data.
- Custom validations are easy to implement, may execute asynchronous actions, and may depend on any value of the form or even external context.
- Manage your form on the client via a
form manager, which:
- Automatically validates your form, asynchronously, as it is edited.
- Caches validation results, only rerunning validations when the value they’re validating or a value they depend on changes, thus performing well on forms with hundreds to thousands of validations.
- Supports dirty/touched field states.
- Has easy to use bindings available for React applications.
- Validates values of your form on the server via a
form validator which:
- Supports running extra server-only validations (e.g. that require database access).
- Access values of your form with Unix-style paths via the form manager or validator.
Show me some code¶
The following example defines the schema and validations of a login form and validates an example form value as one would on the server:
data class LoginForm(var username: String, var password: String) // (1)!
val loginFormSchema = ClassSchema { // (2)!
LoginForm::username { StringSchema(Required() /* (3)! */) }
LoginForm::password { StringSchema(Required(), MinLength(8), PasswordContainsDigit) }
}
object PasswordContainsDigit : Validation<String>() { // (4)!
override fun ValidationContext.validate() = flow {
if (value.none { char -> char.isDigit() }) {
emit(ValidationError("passwordMustContainDigit"))
}
}
}
val loginFormValidator = FormValidator(loginFormSchema) // (5)!
// Within a coroutine: (6)
assertEquals(
listOf(LocatedValidationError("/password" /*(7)!*/, "passwordMustContainDigit")),
loginFormValidator.validate(LoginForm("alice", "huntertwo")).toList(),
)
- Model of our form, specified in standard Kotlin code.
- Definition of our form’s schema, instructing KForm on how to manage and validate it.
- KForm provides built-in validations such as
RequiredorMinLength, among others, for common validation scenarios. - Custom validations can be defined to further validate the form’s data. This validation emits a validation error when the string it is validating doesn’t contain any digits.
- The form validator is typically used on the server-side to validate submitted forms.
- Validations and other KForm features run asynchronously, so they must run within coroutines. For Java servers, KForm provides wrapper utilities around completable futures.
- Paths are used extensively in KForm to point to parts of data within a form. Here, it specifies the location of the validation error.
Supported targets¶
KForm currently supports the following targets (via Kotlin Multiplatform):
- JVM, for server applications.
- JavaScript, for client applications.
KForm further provides idiomatic JavaScript bindings (with TypeScript definitions) for consuming the library from JavaScript code, as well as a React library for integration with React.
Support for other targets such as Android or iOS is possible but not yet implemented.
When to use?¶
KForm is being developed with a main use-case in mind: aiding the development of fairly complicated web-based forms containing dozens to hundreds of validations that should be kept in sync between a client (browser) application and a JVM-based server.
These forms often contain tabular data which, for some users, may end up containing many thousands of rows which have to be validated without degrading user experience: something that is often difficult to achieve with different form validation libraries.
This isn’t to say that KForm won’t fit other use-cases, just that this is the one it mainly caters to.
When deciding whether to use KForm, some constraints should be kept in mind:
- Due to the usage of Kotlin’s standard library and the dependency on certain Kotlin Multiplatform libraries such as kotlinx.coroutines or kotlinx.serialization, the file size of a JavaScript bundle using KForm can be rather large, reaching ~1.2 MB for the rather simple demo in the KForm repository (which does bundle React, but no React component library).
- Thanks to Kotlin Multiplatform, the usage of Gradle is required, which might make it hard to adopt KForm in projects already using different build tools.
- Although not incredibly complicated, the interaction between Kotlin and JavaScript/TypeScript can sometimes be tricky, forcing developers to write “glue code” in Kotlin/JS to make certain objects or functionality more easily accessible from JavaScript.
- We currently don’t provide bindings for any UI library other than React (written in JavaScript/TypeScript, as opposed to React code written in Kotlin).
With this in mind, there are some scenarios in which you likely don’t want to use KForm:
- Your server doesn’t run on the JVM. Even though we provide bindings for use from JavaScript, we currently don’t offer JavaScript bindings for the more server-related parts of the API, such as the form validator, meaning that even with a JavaScript-based server, you will likely have trouble using KForm.
- You have a simple form with only a handful of validations and aren’t already using KForm or other Kotlin dependencies in your client application (in which case the incurred increase in bundle size from pulling KForm together with its Kotlin dependencies might not be worth it).
License¶
KForm is licensed under the Apache License 2.0.