build-status Maven Central

Compose EasyForms

Focus on building your form UI while the library do the heavy work for you.

Features

Built in support for most of the Form widgets in Compose

Examples

Initializing

EasyForms handles process death out of the box 😎.

@Composable
fun BuildMyAwesomeForm(
  onClick: (EasyForms) -> Unit,
) {
  Scaffold(
    ....
  ) {
    // BuildEasyForms fun provided by EasyForms
    BuildEasyForms { easyForm ->
      Column {
        // your Composables
        LoginButton(easyForms) { onClick(easyForms) }
      }
    }
  }
}
TextField

EasyForms provide some of the commom used textfields validation:

  • Email validation

@Composable
fun EmailTextField(easyForms: EasyForms) {
  val textFieldState = easyForms.getTextFieldState(
    key = MyFormKeys.EMAIL,
    easyFormsValidationType = EmailValidationType,
    defaultValue = "",
  )
  val state = textFieldState.state
  TextField(
    value = state.value,
    onValueChange = textFieldState.onValueChangedCallback,
    isError = textFieldState.errorState.value == EasyFormsErrorState.INVALID,
  )
}
  • Password validation

@Composable
fun PasswordTextField(easyForms: EasyForms) {
  val textFieldState = easyForms.getTextFieldState(
    key = MyFormKeys.PASSWORD,
    easyFormsValidationType = PasswordValidationType,
    defaultValue = "",
  )
  val state = textFieldState.state
  TextField(
    value = state.value,
    onValueChange = textFieldState.onValueChangedCallback,
    isError = textFieldState.errorState.value == EasyFormsErrorState.INVALID,
  )
}
  • Phone validation

@Composable
fun PhoneTextField(easyForms: EasyForms) {
  val textFieldState = easyForms.getTextFieldState(
    key = MyFormKeys.PHONE,
    easyFormsValidationType = PhoneValidationType,
    defaultValue = "",
  )
  val state = textFieldState.state
  TextField(
    value = state.value,
    onValueChange = textFieldState.onValueChangedCallback,
    isError = textFieldState.errorState.value == EasyFormsErrorState.INVALID,
  )
}
  • URL validation

@Composable
fun UrlTextField(easyForms: EasyForms) {
  val textFieldState = easyForms.getTextFieldState(
    key = MyFormKeys.URL,
    easyFormsValidationType = UrlValidationType,
    defaultValue = "",
  )
  val state = textFieldState.state
  TextField(
    value = state.value,
    onValueChange = textFieldState.onValueChangedCallback,
    isError = textFieldState.errorState.value == EasyFormsErrorState.INVALID,
  )
}
  • Name validation

@Composable
fun NameTextField(easyForms: EasyForms) {
  val textFieldState = easyForms.getTextFieldState(
    key = MyFormKeys.NAME,
    easyFormsValidationType = NameValidationType,
    defaultValue = "",
  )
  val state = textFieldState.state
  TextField(
    value = state.value,
    onValueChange = textFieldState.onValueChangedCallback,
    isError = textFieldState.errorState.value == EasyFormsErrorState.INVALID,
  )
}
  • Cards validation

@Composable
fun CardTextField(easyForms: EasyForms) {
  val textFieldState = easyForms.getTextFieldState(
    key = MyFormKeys.CARD,
    easyFormsValidationType = CardValidationType,
    defaultValue = "",
  )
  val state = textFieldState.state
  TextField(
    value = state.value,
    onValueChange = textFieldState.onValueChangedCallback,
    isError = textFieldState.errorState.value == EasyFormsErrorState.INVALID,
  )
}

Custom Validation:

  • You can provide your own validator for EasyForms to use, for example you could provide a custom
    regex only, a min and/or max length only or combine them all together and EasyForms will ensure the
    validity based on your configuration.

object MyCustomValidationType : EasyFormsValidationType(
  regex = "MyAwesomeRegex",
  minLength = 10,
  maxLength = 30,
)

object MyCustomRegexValidationType : EasyFormsValidationType(
  regex = "MyAwesomeRegex"
)

object MyCustomLengthValidationType : EasyFormsValidationType(
  minLength = 20,
  maxLength = 50,
)

To use your custom validation:

@Composable
fun MyTextField(easyForms: EasyForms) {
  val textFieldState = easyForms.getTextFieldState(MyFormKeys.MY_KEY, MyCustomValidationType)
  val state = textFieldState.state
  TextField(
    value = state.value,
    onValueChange = textFieldState.onValueChangedCallback,
    isError = textFieldState.errorState.value == EasyFormsErrorState.INVALID,
  )
}
Checkbox

@Composable
fun CheckboxLayout(easyForms: EasyForms) {
  val checkboxState = easyForms.getCheckboxState(
    MyFormKeys.CHECKBOX,
    defaultValue = false,
    isRequired = true,
  )
  val checkedState = checkboxState.state
  Checkbox(
    checked = checkedState.value,
    onCheckedChange = checkboxState.onValueChangedCallback,
  )
}
TriStateCheckbox

@Composable
fun TriCheckboxLayout(easyForms: EasyForms) {
  val checkboxState = easyForms.getTriCheckboxState(
    MyFormKeys.TRI_CHECKBOX,
    defaultValue = ToggleableState.Indeterminate,
    isRequired = true,
  )
  val checkedState = checkboxState.state
  TriStateCheckbox(
    state = checkedState.value,
    onClick = checkboxState.onClick,
  )
}
RadioButton

@Composable
fun RadioButtonLayout(easyForms: EasyForms) {
  val radioButtonState = easyForms.getRadioButtonState(
    MyFormKeys.RADIO_BUTTON,
    defaultValue = false,
    isRequired = true,
  )
  val checkedState = radioButtonState.state
  RadioButton(
    state = checkedState.value,
    onClick = radioButtonState.onClick,
  )
}
Switch

@Composable
fun SwitchLayout(easyForms: EasyForms) {
  val switchState = easyForms.getSwitchState(
    MyFormKeys.SWITCH,
    defaultValue = false,
    isRequired = true,
  )
  val checkedState = switchState.state
  Checkbox(
    checked = checkedState.value,
    onCheckedChange = switchState.onValueChangedCallback,
  )
}
Slider

@Composable
fun SliderLayout(easyForms: EasyForms) {
  val state = easyForms.getSliderState(
    key = MyFormKeys.SLIDER,
    defaultValue = 0F,
    isRequired = true,
  )
  val sliderPosition = state.state
  Slider(
    value = sliderPosition.value,
    onValueChange = state.onValueChangedCallback,
    onValueChangeFinished = state.onValueChangeFinished,
  )
}
RangeSlider

@Composable
fun RangeSliderLayout(easyForms: EasyForms) {
  val state = easyForms.getRangeSliderState(
    key = MyFormKeys.RANGE_SLIDER,
    defaultValue = 0F..0F,
    isRequired = true
  )
  val sliderPosition = state.state
  RangeSlider(
    value = sliderPosition.value,
    onValueChange = state.onValueChangedCallback,
    onValueChangeFinished = state.onValueChangeFinished,
  )
}
CustomState

You can use one of the already defined EasyFormsState for most cases, however when you need
something that EasyFormsState doesn’t provide then you could simply create your own. Please
follow this link
for more details.

ObserveState

@Composable
fun LoginButton(
  easyForms: EasyForms,
  onClick: () -> Unit,
) {
  val errorStates = easyForms.observeFormStates()
  Button(
    onClick = onClick,
    modifier = Modifier.fillMaxWidth(),
    enabled = errorStates.value.all {
      it.value == EasyFormsErrorState.VALID
    }
  ) {
    Text("Submit")
  }
}

For more example please refer to the example app.

VideoEditor_20210921_094725.mp4


Download Maven Central

repositories {
  mavenCentral()
}

dependencies {
  implementation("com.github.k0shk0sh:compose-easyforms:<version>")
}

Contributions

Please contribute! We will gladly review any pull requests. Make sure to read
the Contributing page first though.

GitHub

https://github.com/k0shk0sh/ComposeEasyForms