LiteQuest

A lightweight, FHIR-inspired questionnaire library for Kotlin Multiplatform applications.
This library is :construction: work in progress and not production ready.
Installation
Add to your build.gradle.kts:
kotlin {
sourceSets {
commonMain {
dependencies {
implementation("io.github.ellykits.litequest:litequest-library:1.0.0-beta01")
}
}
}
}
Usage
Basic Questionnaire
Paginated Questionnaires
val paginatedQuestionnaire = PaginatedQuestionnaire(
id = "health-survey",
title = ,
pages = listOf(
QuestionnairePage(
id = ,
title = ,
order = ,
items = listOf()
),
QuestionnairePage(
id = ,
title = ,
order = ,
items = listOf()
)
)
)
flatQuestionnaire = Questionnaire(
id = paginatedQuestionnaire.id,
title = paginatedQuestionnaire.title,
version = paginatedQuestionnaire.version,
items = paginatedQuestionnaire.pages.flatMap { it.items }
)
evaluator = LiteQuestEvaluator(flatQuestionnaire)
manager = QuestionnaireManager(flatQuestionnaire, evaluator)
QuestionnaireScreen(
type = QuestionnaireType.Paginated(paginatedQuestionnaire),
manager = manager,
onModeChange = ,
onSubmit = { },
onDismiss = { }
)
QuestionnaireScreen Parameters
Embedded Questionnaire
EmbeddedQuestionnaire renders only the form fields — no Scaffold, no TopAppBar, no submit button, no dismiss dialogs. It sizes to fit its items, so the host screen owns the layout, scroll, and submission logic. Validation errors still appear inline as the user interacts with each field.
Read answers at any time via manager.state:
val response = manager.state.value.response
QuestionnaireScreen remains the full-screen component that manages its own Scaffold, system bar insets, submit flow, and dismiss dialogs. Use EmbeddedQuestionnaire when you want to own all of that yourself.
JsonLogic Expressions
Visibility conditions (skip logic) support both simple and nested paths:
Item(
linkId = ,
text = ,
visibleIf = buildJsonObject {
put(, buildJsonArray {
add(buildJsonObject { put(, ) })
add(JsonPrimitive())
})
}
)
Item(
linkId = ,
text = ,
visibleIf = buildJsonObject {
put(, buildJsonArray {
add(buildJsonObject { put(, ) })
add(JsonPrimitive())
})
}
)
Item(
linkId = ,
text = ,
visibleIf = buildJsonObject {
put(, buildJsonObject { put(, ) })
}
)
Calculated expressions:
Custom Widgets
JsonLogic Extensibility
LiteQuestEvaluator accepts a JsonLogicEvaluator instance:
val evaluator = LiteQuestEvaluator(questionnaire, JsonLogicEvaluator())
val manager = QuestionnaireManager(questionnaire, evaluator)
Custom operators are not yet pluggable through overrides. If you need extra operators, extend JsonLogicEvaluator.kt in the library source.
Architecture
LiteQuest follows a clean, layered architecture:
library/
├── model/ # Data structures (Questionnaire, Item, Response)
├── engine/ # JsonLogic evaluation, validation, visibility, calculations
├── state/ # QuestionnaireManager - reactive state orchestration
├── ui/ # Compose UI components
│ ├── screen/ # QuestionnaireScreen (full-screen), EmbeddedQuestionnaire (fields only)
│ ├── widget/ # Input widgets for different item types
│ ├── summary/ # Summary/review page components
│ ├── pagination/ # Multi-page support with navigation
│ └── renderer/ # Form rendering logic
└── util/ # Helper utilities
Key Concepts
JsonLogic Expressions
LiteQuest uses a custom Kotlin Multiplatform implementation of JsonLogic for all dynamic behavior. This pure-Kotlin evaluator works across all platforms (Android, iOS, Desktop, Web) without external dependencies.
Supported Operators:
Implementation:
JsonLogicEvaluator.kt - Core evaluator engine
VisibilityEngine.kt - Skip logic using JsonLogic
CalculatedValuesEngine.kt - Computed fields using JsonLogic
ValidationEngine.kt - Custom validation rules using JsonLogic
Reactive State Management
State updates propagate automatically:
Answer Change → Recalculate Values → Update Visibility → Revalidate → Emit New State
Widget Types
Running the Demo
Desktop
./gradlew :demo:desktopDemo:desktopRun
Android
./gradlew :demo:androidDemo:installDebug
Web (JS)
./gradlew :demo:webDemo:jsBrowserDevelopmentRun
Web (Wasm)
./gradlew :demo:webDemo:wasmJsBrowserDevelopmentRun
iOS
Open demo/iosDemo/iosDemo.xcodeproj in Xcode and run on a simulator or device.
Development
Running Tests
./gradlew :library:allTests
./gradlew :library:desktopTest
./gradlew :library:jsBrowserTest
./gradlew :library:androidUnitTest
./gradlew :library:iosSimulatorArm64Test
Building
./gradlew :library:build
./gradlew :demo:androidDemo:assembleDebug
Platform Support
Documentation
- LiteQuest Technical Specification v1.0.0 - Core engine architecture and JsonLogic evaluation
Contributing
We welcome contributions! Please see CONTRIBUTING.md for guidelines.
Development Setup
- Clone the repository
- Open in IntelliJ IDEA or Android Studio
- Run tests:
./gradlew :library:allTests
- Run demo:
./gradlew :demo:desktopDemo:desktopRun
Code Style
- Follow Kotlin Coding Conventions
- Use meaningful names
- Keep functions small and focused
- Write tests for new features
License
Copyright 2025 LiteQuest Contributors
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
https://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.
Acknowledgments
Based on the LiteQuest Technical Specification v1.0.0, inspired by HL7 FHIR Questionnaire resources.
Special thanks to all contributors.
Made with ❤️ by the LiteQuest community