{"id":30754360,"url":"https://github.com/k0shk0sh/composeeasyforms","last_synced_at":"2025-09-04T09:09:55.603Z","repository":{"id":46999885,"uuid":"405772156","full_name":"k0shk0sh/ComposeEasyForms","owner":"k0shk0sh","description":"Compose easy forms validation library","archived":false,"fork":false,"pushed_at":"2021-09-30T10:28:41.000Z","size":617,"stargazers_count":25,"open_issues_count":0,"forks_count":2,"subscribers_count":5,"default_branch":"main","last_synced_at":"2024-05-02T00:54:18.593Z","etag":null,"topics":["android-compose","android-compose-forms","android-compose-library","android-compose-state","android-compose-validation","compose","compose-forms","kotlin","validation"],"latest_commit_sha":null,"homepage":"https://k0shk0sh.github.io/ComposeEasyForms/","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/k0shk0sh.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-09-12T23:01:44.000Z","updated_at":"2024-03-29T11:20:42.000Z","dependencies_parsed_at":"2022-07-21T06:32:28.800Z","dependency_job_id":null,"html_url":"https://github.com/k0shk0sh/ComposeEasyForms","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/k0shk0sh/ComposeEasyForms","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/k0shk0sh%2FComposeEasyForms","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/k0shk0sh%2FComposeEasyForms/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/k0shk0sh%2FComposeEasyForms/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/k0shk0sh%2FComposeEasyForms/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/k0shk0sh","download_url":"https://codeload.github.com/k0shk0sh/ComposeEasyForms/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/k0shk0sh%2FComposeEasyForms/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273581314,"owners_count":25131393,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-04T02:00:08.968Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android-compose","android-compose-forms","android-compose-library","android-compose-state","android-compose-validation","compose","compose-forms","kotlin","validation"],"created_at":"2025-09-04T09:09:06.044Z","updated_at":"2025-09-04T09:09:55.560Z","avatar_url":"https://github.com/k0shk0sh.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"![build-status](https://github.com/k0shk0sh/ComposeEasyForms/actions/workflows/build.yml/badge.svg) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.k0shk0sh/compose-easyforms/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.k0shk0sh/compose-easyforms)\n\n# Compose EasyForms\n\nFocus on building your form UI while the library do the heavy work for you.\n\n## Features\n\n### Built in support for most of the Form widgets in Compose\n\n- [Initializing](#Initializing)\n- [TextField](#TextField)\n- [Checkbox](#Checkbox)\n- [TriStateCheckbox](#TriStateCheckbox)\n- [RadioButton](#RadioButton)\n- [Switch](#Switch)\n- [Slider](#Slider)\n- [RangeSlider](#RangeSlider)\n- [Create your own](#CustomState)\n- [Obsever Form state](#ObserveState)\n\n## Examples\n\n#### Initializing\n\n\u003e EasyForms handles process death out of the box 😎.\n\n```kotlin\n@Composable\nfun BuildMyAwesomeForm(\n  onClick: (EasyForms) -\u003e Unit,\n) {\n  Scaffold(\n    ....\n  ) {\n    // BuildEasyForms fun provided by EasyForms\n    BuildEasyForms { easyForm -\u003e\n      Column {\n        // your Composables\n        LoginButton(easyForms) { onClick(easyForms) }\n      }\n    }\n  }\n}\n```\n\n##### TextField\n\nEasyForms provide some of the commom used textfields validation:\n\n- Email validation\n\n```kotlin\n@Composable\nfun EmailTextField(easyForms: EasyForms) {\n  val textFieldState = easyForms.getTextFieldState(\n    key = MyFormKeys.EMAIL,\n    easyFormsValidationType = EmailValidationType,\n    defaultValue = \"\",\n  )\n  val state = textFieldState.state\n  TextField(\n    value = state.value,\n    onValueChange = textFieldState.onValueChangedCallback,\n    isError = textFieldState.errorState.value == EasyFormsErrorState.INVALID,\n  )\n}\n```\n\n- Password validation\n\n```kotlin\n@Composable\nfun PasswordTextField(easyForms: EasyForms) {\n  val textFieldState = easyForms.getTextFieldState(\n    key = MyFormKeys.PASSWORD,\n    easyFormsValidationType = PasswordValidationType,\n    defaultValue = \"\",\n  )\n  val state = textFieldState.state\n  TextField(\n    value = state.value,\n    onValueChange = textFieldState.onValueChangedCallback,\n    isError = textFieldState.errorState.value == EasyFormsErrorState.INVALID,\n  )\n}\n```\n\n- Phone validation\n\n```kotlin\n@Composable\nfun PhoneTextField(easyForms: EasyForms) {\n  val textFieldState = easyForms.getTextFieldState(\n    key = MyFormKeys.PHONE,\n    easyFormsValidationType = PhoneValidationType,\n    defaultValue = \"\",\n  )\n  val state = textFieldState.state\n  TextField(\n    value = state.value,\n    onValueChange = textFieldState.onValueChangedCallback,\n    isError = textFieldState.errorState.value == EasyFormsErrorState.INVALID,\n  )\n}\n```\n\n- URL validation\n\n```kotlin\n@Composable\nfun UrlTextField(easyForms: EasyForms) {\n  val textFieldState = easyForms.getTextFieldState(\n    key = MyFormKeys.URL,\n    easyFormsValidationType = UrlValidationType,\n    defaultValue = \"\",\n  )\n  val state = textFieldState.state\n  TextField(\n    value = state.value,\n    onValueChange = textFieldState.onValueChangedCallback,\n    isError = textFieldState.errorState.value == EasyFormsErrorState.INVALID,\n  )\n}\n```\n\n- Name validation\n\n```kotlin\n@Composable\nfun NameTextField(easyForms: EasyForms) {\n  val textFieldState = easyForms.getTextFieldState(\n    key = MyFormKeys.NAME,\n    easyFormsValidationType = NameValidationType,\n    defaultValue = \"\",\n  )\n  val state = textFieldState.state\n  TextField(\n    value = state.value,\n    onValueChange = textFieldState.onValueChangedCallback,\n    isError = textFieldState.errorState.value == EasyFormsErrorState.INVALID,\n  )\n}\n```\n\n- Cards validation\n\n```kotlin\n@Composable\nfun CardTextField(easyForms: EasyForms) {\n  val textFieldState = easyForms.getTextFieldState(\n    key = MyFormKeys.CARD,\n    easyFormsValidationType = CardValidationType,\n    defaultValue = \"\",\n  )\n  val state = textFieldState.state\n  TextField(\n    value = state.value,\n    onValueChange = textFieldState.onValueChangedCallback,\n    isError = textFieldState.errorState.value == EasyFormsErrorState.INVALID,\n  )\n}\n```\n\nCustom Validation:\n\n- You can provide your own validator for EasyForms to use, for example you could provide a custom\n  regex only, a min and/or max length only or combine them all together and EasyForms will ensure the\n  validity based on your configuration.\n\n```kotlin\nobject MyCustomValidationType : EasyFormsValidationType(\n  regex = \"MyAwesomeRegex\",\n  minLength = 10,\n  maxLength = 30,\n)\n\nobject MyCustomRegexValidationType : EasyFormsValidationType(\n  regex = \"MyAwesomeRegex\"\n)\n\nobject MyCustomLengthValidationType : EasyFormsValidationType(\n  minLength = 20,\n  maxLength = 50,\n)\n```\n\nTo use your custom validation:\n\n```kotlin\n@Composable\nfun MyTextField(easyForms: EasyForms) {\n  val textFieldState = easyForms.getTextFieldState(MyFormKeys.MY_KEY, MyCustomValidationType)\n  val state = textFieldState.state\n  TextField(\n    value = state.value,\n    onValueChange = textFieldState.onValueChangedCallback,\n    isError = textFieldState.errorState.value == EasyFormsErrorState.INVALID,\n  )\n}\n```\n\n##### Checkbox\n\n```kotlin\n@Composable\nfun CheckboxLayout(easyForms: EasyForms) {\n  val checkboxState = easyForms.getCheckboxState(\n    MyFormKeys.CHECKBOX,\n    defaultValue = false,\n    isRequired = true,\n  )\n  val checkedState = checkboxState.state\n  Checkbox(\n    checked = checkedState.value,\n    onCheckedChange = checkboxState.onValueChangedCallback,\n  )\n}\n```\n\n##### TriStateCheckbox\n\n```kotlin\n@Composable\nfun TriCheckboxLayout(easyForms: EasyForms) {\n  val checkboxState = easyForms.getTriCheckboxState(\n    MyFormKeys.TRI_CHECKBOX,\n    defaultValue = ToggleableState.Indeterminate,\n    isRequired = true,\n  )\n  val checkedState = checkboxState.state\n  TriStateCheckbox(\n    state = checkedState.value,\n    onClick = checkboxState.onClick,\n  )\n}\n```\n\n##### RadioButton\n\n```kotlin\n@Composable\nfun RadioButtonLayout(easyForms: EasyForms) {\n  val radioButtonState = easyForms.getRadioButtonState(\n    MyFormKeys.RADIO_BUTTON,\n    defaultValue = false,\n    isRequired = true,\n  )\n  val checkedState = radioButtonState.state\n  RadioButton(\n    state = checkedState.value,\n    onClick = radioButtonState.onClick,\n  )\n}\n```\n\n##### Switch\n\n```kotlin\n@Composable\nfun SwitchLayout(easyForms: EasyForms) {\n  val switchState = easyForms.getSwitchState(\n    MyFormKeys.SWITCH,\n    defaultValue = false,\n    isRequired = true,\n  )\n  val checkedState = switchState.state\n  Checkbox(\n    checked = checkedState.value,\n    onCheckedChange = switchState.onValueChangedCallback,\n  )\n}\n```\n\n##### Slider\n\n```kotlin\n@Composable\nfun SliderLayout(easyForms: EasyForms) {\n  val state = easyForms.getSliderState(\n    key = MyFormKeys.SLIDER,\n    defaultValue = 0F,\n    isRequired = true,\n  )\n  val sliderPosition = state.state\n  Slider(\n    value = sliderPosition.value,\n    onValueChange = state.onValueChangedCallback,\n    onValueChangeFinished = state.onValueChangeFinished,\n  )\n}\n```\n\n##### RangeSlider\n\n```kotlin\n@Composable\nfun RangeSliderLayout(easyForms: EasyForms) {\n  val state = easyForms.getRangeSliderState(\n    key = MyFormKeys.RANGE_SLIDER,\n    defaultValue = 0F..0F,\n    isRequired = true\n  )\n  val sliderPosition = state.state\n  RangeSlider(\n    value = sliderPosition.value,\n    onValueChange = state.onValueChangedCallback,\n    onValueChangeFinished = state.onValueChangeFinished,\n  )\n}\n```\n\n##### CustomState\n\nYou can use one of the already defined `EasyFormsState` for most cases, however when you need\nsomething that `EasyFormsState` doesn't provide then you could simply create your own. Please\nfollow [this link](https://github.com/k0shk0sh/ComposeEasyForms/blob/main/app/src/main/java/com/github/k0shk0sh/compose/easyforms/example/ui/components/Dropdown.kt#L22)\nfor more details.\n\n##### ObserveState\n\n```kotlin\n@Composable\nfun LoginButton(\n  easyForms: EasyForms,\n  onClick: () -\u003e Unit,\n) {\n  val errorStates = easyForms.observeFormStates()\n  Button(\n    onClick = onClick,\n    modifier = Modifier.fillMaxWidth(),\n    enabled = errorStates.value.all {\n      it.value == EasyFormsErrorState.VALID\n    }\n  ) {\n    Text(\"Submit\")\n  }\n}\n```\n\n\u003e For more example please refer to the example app.\n\n\nhttps://user-images.githubusercontent.com/960767/134132572-09648756-68fa-4184-ac87-71979eda61f5.mp4\n\n\n## Download [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.k0shk0sh/compose-easyforms/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.k0shk0sh/compose-easyforms)\n\n\n```kotlin\nrepositories {\n  mavenCentral()\n}\n\ndependencies {\n  implementation(\"com.github.k0shk0sh:compose-easyforms:\u003cversion\u003e\")\n}\n```\n\n## Contributions\n\nPlease contribute! We will gladly review any pull requests. Make sure to read\nthe [Contributing](.github/CONTRIBUTING.md) page first though.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fk0shk0sh%2Fcomposeeasyforms","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fk0shk0sh%2Fcomposeeasyforms","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fk0shk0sh%2Fcomposeeasyforms/lists"}