A lightweight, FHIR-inspired questionnaire library for Kotlin Multiplatform applications.
litequestdemo_.mov
- ✅ Reactive State - StateFlow-based automatic state propagation
- ✅ Dynamic Calculations - JsonLogic expressions for validation, visibility, and computed values
- ✅ Type-Safe - Full Kotlin type safety with kotlinx.serialization
- ✅ Cross-Platform - Single codebase for Android, iOS, Desktop, and Web
- ✅ Extensible - Extend JsonLogicEvaluator for custom evaluation logic
- ✅ Unified Questionnaire Screen - Single component for Edit and Summary modes
- ✅ Multi-Page Support - Pagination with progress indicators and navigation
- ✅ Rich Widgets - Text, Decimal, Integer, Boolean, Choice, Date, Time, Display, Group widgets
- ✅ Repeating Groups - Dynamic add/remove of grouped items
- ✅ Card-Based Summary - Beautiful summary view with page organization
- ✅ Theme Support - Light and Dark themes with Material 3 design
- 🔄 Multi-language Support - Remote translation loading with caching
- 🔄 Media Widgets - Photo, Barcode, Location, Signature widgets
- 🔄 FHIR Conversion - Bidirectional FHIR Questionnaire conversion
Add to your build.gradle.kts:
kotlin {
sourceSets {
commonMain {
dependencies {
implementation("io.github.ellykits.litequest:litequest-library:1.0.0-alpha02")
}
}
}
}@Composable
fun MyQuestionnaireScreen() {
// Define a questionnaire
val questionnaire = Questionnaire(
id = "patient-intake",
version = "1.0.0",
title = "Patient Intake Form",
items = listOf(
Item(
linkId = "name",
type = ItemType.TEXT,
text = "What is your full name?",
required = true
),
Item(
linkId = "age",
type = ItemType.INTEGER,
text = "What is your age?",
required = true
)
)
)
// Initialize manager with evaluator
val evaluator = remember { LiteQuestEvaluator(questionnaire) }
val manager = remember { QuestionnaireManager(questionnaire, evaluator) }
val state by manager.state.collectAsState()
// Mode switching between Edit and Summary
var mode by remember { mutableStateOf(QuestionnaireMode.Edit) }
// Render the questionnaire
QuestionnaireScreen(
type = QuestionnaireType.Single(questionnaire),
state = state,
mode = mode,
onAnswerChange = { linkId, value -> manager.updateAnswer(linkId, value) },
onSubmit = {
// Handle form submission
println("Form submitted: ${state.response}")
},
onModeChange = { newMode -> mode = newMode },
onDismiss = { /* Handle dismiss */ }
)
}
// For multi-page questionnaires
val paginatedQuestionnaire = PaginatedQuestionnaire(
id = "health-survey",
title = "Health Survey",
pages = listOf(
QuestionnairePage(
id = "demographics",
title = "Demographics",
order = 0,
items = listOf(/* page 1 items */)
),
QuestionnairePage(
id = "health-history",
title = "Health History",
order = 1,
items = listOf(/* page 2 items */)
)
)
)
QuestionnaireScreen(
type = QuestionnaireType.Paginated(paginatedQuestionnaire),
state = state,
onAnswerChange = { linkId, value -> manager.updateAnswer(linkId, value) },
onSubmit = { /* Handle submission */ },
onDismiss = { /* Handle dismiss */ }
)The project includes a Compose Multiplatform demo app showcasing library features.
./gradlew :demo:run./gradlew :demo:installDebugOpen iosApp/iosApp.xcodeproj in Xcode and run.
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 - unified Edit/Summary screen
│ ├── widget/ # Input widgets for different item types
│ ├── summary/ # Summary/review page components
│ ├── pagination/ # Multi-page support with navigation
│ └── renderer/ # Form rendering logic
└── util/ # Helper utilitiesFor detailed architecture and design decisions, see Form Visualizer Technical Specification v1.0.0.
All dynamic behavior is expressed using JsonLogic, a JSON-based expression language:
// Visibility condition
Item(
linkId = "symptoms",
text = "Please describe your symptoms",
visibleIf = buildJsonObject {
put("==", buildJsonObject {
put("0", buildJsonObject { put("var", "has-symptoms") })
put("1", true)
})
}
)
// Calculated value
CalculatedValue(
name = "bmi",
expression = buildJsonObject {
put("/", buildJsonObject {
put("0", buildJsonObject { put("var", "weight") })
put("1", buildJsonObject {
put("*", buildJsonObject {
put("0", buildJsonObject { put("var", "height") })
put("1", buildJsonObject { put("var", "height") })
})
})
})
}
)State updates propagate automatically:
Answer Change → Recalculate Values → Update Visibility → Revalidate → Emit New StateDecouple translations from questionnaire definitions:
val translationManager = TranslationManager(
loader = TranslationLoader(),
cache = TranslationCache()
)
// Load translations on demand
translationManager.loadTranslation("en", "https://example.com/translations/en.json")lite-quest/
├── library/ # Core KMP library
│ ├── src/
│ │ ├── commonMain/
│ │ ├── commonTest/
│ │ ├── androidMain/
│ │ ├── desktopMain/
│ │ ├── iosMain/
│ │ └── wasmJsMain/
│ └── build.gradle.kts
├── demo/ # Compose Multiplatform demo app
│ └── src/
└── settings.gradle.kts# Run all tests
./gradlew :library:desktopTest
# Run platform-specific tests
./gradlew :library:androidUnitTest
./gradlew :library:iosSimulatorArm64Test# Build library
./gradlew :library:assemble
# Build demo app
./gradlew :demo:assembleDebugWe welcome contributions! Please see CONTRIBUTING.md for guidelines.
- Clone the repository
- Open in IntelliJ IDEA or Android Studio
- Run tests:
./gradlew :library:desktopTest - Run demo:
./gradlew :demo:run
- Follow Kotlin Coding Conventions
- Use meaningful names
- Keep functions small and focused
- Write tests for new features
| Platform | Status | Min Version |
|---|---|---|
| Android | ✅ Stable | API 24 (Android 7.0) |
| iOS | ✅ Stable | iOS 14.0+ |
| Desktop | ✅ Stable | JVM 11+ |
| Web (WASM) | Modern browsers |
- Kotlin 2.0.21+
- kotlinx-serialization 1.7.3+
- kotlinx-coroutines 1.9.0+
- kotlinx-datetime 0.6.1+
- ktor-client 3.0.1+
See gradle/libs.versions.toml for complete dependency list.
- LiteQuest Technical Specification v1.0.0 - Core engine architecture and JsonLogic evaluation
- Form Visualizer Technical Specification v1.0.0 - UI components and form rendering
- Demo App - Working examples for all platforms
- 💬 Discussions - Ask questions and share ideas
- 🐛 Issues - Report bugs and request features
- 📧 Mailing List - Development announcements
- Multi-language support with remote translation loading
- FHIR Questionnaire bidirectional conversion
- File attachment and media upload support
- Media widgets (Photo, Barcode, Location, Signature)
- Advanced validation rules with custom validators
- Form analytics and telemetry
- Visual form builder/editor
- Form versioning and migration tools
- Advanced conditional logic builder
See Form Visualizer Technical Specification v1.0.0 for more details.
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
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.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