A lightweight Kotlin Multiplatform radial context menu library for Android and Desktop JVM.
RadialMenu supports Compose APIs (RadialMenuWrapper + RadialMenuOverlay) and Android View APIs (RadialMenuView), with trigger modes for long press, right click, and keyboard hold interactions.
| RadialMenu | Kotlin | Compose Multiplatform | AGP | Android Min SDK | Desktop Min JDK |
|---|---|---|---|---|---|
| 1.0.5 | 2.1.20 | 1.7+ | 8.5+ | 21 | 17 |
RadialMenu follows Semantic Versioning.
Minor versions add features without breaking public API; major versions may include breaking changes (see CHANGELOG.md).
| Platform | Status |
|---|---|
| Android (Compose + View) | Supported |
| Desktop JVM (Compose) | Supported |
- Kotlin Multiplatform support for Android and Desktop JVM.
- Multiple trigger modes with platform defaults via
RadialMenuTriggerMode.Auto. - Trigger options:
LongPress,SecondaryClick,KeyboardHold(key). - Position-aware rotation controls for touch and pointer modes.
- Drag/flick directional selection with smooth scaling feedback.
- Edge-hug corner layout (opt-in) for constrained corner spawns.
- Badge support (
badgeCountandbadgeText). - Active/inactive icon state support.
- Compose overlay color and animation customization.
- Android View support with XML attributes and runtime configuration.
- POM declares only
kotlin-stdlib(consumer provides Compose/AndroidX).
Full docs: gawwr4v.github.io/RadialMenu
dependencies {
implementation("io.github.gawwr4v:radialmenu:1.0.5")
}// app/build.gradle.kts
dependencies {
implementation("io.github.gawwr4v:radialmenu:1.0.5")
// Required only if you use the Painter-based item constructor directly.
// Not required when using DrawableRes/Drawable overloads.
implementation("androidx.compose.ui:ui:1.8.0")
}// app/build.gradle.kts
plugins {
id("org.jetbrains.kotlin.plugin.compose") version "2.1.0"
}
android {
buildFeatures {
compose = true
}
}
dependencies {
implementation("io.github.gawwr4v:radialmenu:1.0.5")
implementation("androidx.compose.ui:ui:1.8.0")
implementation("androidx.compose.material3:material3:1.3.0")
implementation("androidx.activity:activity-compose:1.9.0")
}dependencies {
implementation("io.github.gawwr4v:radialmenu:1.0.5")
implementation(compose.desktop.currentOs)
}Desktop minimum runtime: Java 17.
import io.github.gawwr4v.radialmenu.*
val items = listOf(
RadialMenuItem(id = 1, icon = sharePainter, label = "Share"),
RadialMenuItem(id = 2, icon = likePainter, label = "Like"),
RadialMenuItem(id = 3, icon = savePainter, label = "Save")
)
Box {
RadialMenuWrapper(
items = items,
onItemSelected = { item -> handleSelection(item) }
) {
Content()
}
RadialMenuOverlay(items = items)
}RadialMenuWrapper supports:
RadialMenuTriggerMode.Auto(default)RadialMenuTriggerMode.LongPress(positionAware = true)RadialMenuTriggerMode.SecondaryClick(positionAware = false)RadialMenuTriggerMode.KeyboardHold(key = Key.Q)
Auto resolves to:
- Android:
LongPress(positionAware = true) - Desktop:
SecondaryClick(positionAware = false)
KeyboardHold behavior:
- Menu opens at screen center.
- Selection is angle-based pie-slice style.
- Flick direction is calibrated from cursor position at key down.
- Selection commits on key release.
- Edge-hug is automatically skipped for center-spawned menus.
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<io.github.gawwr4v.radialmenu.RadialMenuView
android:id="@+id/radialMenu"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:rm_menuRadius="90dp"
app:rm_iconSize="32dp"
app:rm_accentColor="@android:color/white" />
</FrameLayout>val radialMenu = findViewById<RadialMenuView>(R.id.radialMenu)
val items = listOf(
RadialMenuItem(context = this, id = 1, iconRes = R.drawable.ic_share, label = "Share"),
RadialMenuItem(context = this, id = 2, iconRes = R.drawable.ic_like, label = "Like"),
RadialMenuItem(context = this, id = 3, iconRes = R.drawable.ic_save, label = "Save")
)
radialMenu.setItems(items)
radialMenu.enableEdgeHugLayout = true
radialMenu.triggerMode = RadialMenuTriggerMode.LongPress(positionAware = true)
radialMenu.onItemSelected = { item -> handleSelection(item) }
RadialMenuViewsupportsLongPressandSecondaryClick.
KeyboardHoldis accepted for API symmetry but not implemented in the View system.
Default API:
RadialMenuItem(id = 1, icon = painter, label = "Share")Android resource overload:
RadialMenuItem(context = this, id = 1, iconRes = R.drawable.ic_share, label = "Share")Android drawable overload:
RadialMenuItem(id = 1, icon = drawable, label = "Share")Desktop uses Painter icons.
Edge-hug is opt-in:
RadialMenuWrapper(
items = items,
onItemSelected = { /* ... */ },
enableEdgeHugLayout = true
) { Content() }When the menu opens in a true corner with 4+ items, RadialMenu can switch to corner-aware edge-hug placement.
For center-spawned keyboard menus, edge-hug is automatically bypassed.
- Optimal:
4-8items. - Maximum recommended:
8items for touch ergonomics. - No hard item-count limit is enforced by the library.
Symptom: Unresolved reference: RadialMenuView.
Fix:
implementation("io.github.gawwr4v:radialmenu:1.0.5@aar")Verify with:
./gradlew :app:dependencies
./gradlew :app:dependencyInsight --dependency radialmenu --configuration releaseRuntimeClasspathSymptom: class file version 65.0.
Cause: pre-1.0.5 artifact on Java 17 runtime.
Fix: upgrade to 1.0.5 or run Java 21+ for older artifacts.
Fix option 1:
implementation("androidx.compose.ui:ui:1.8.0")Fix option 2: use iconRes/Drawable overloads instead of direct Painter.
| Feature | RadialMenu | Typical Android-only alternatives |
|---|---|---|
| Android + Desktop JVM | Yes | Usually Android only |
| Kotlin Multiplatform | Yes | Usually no |
| Compose + View API mix | Yes | Usually one UI stack |
| Trigger modes | Auto / LongPress / SecondaryClick / KeyboardHold | Usually long press only |
| Edge-aware corner strategy | Yes | Often missing |
| Maven Central publish | Yes | Often JitPack-only |
- Kotlin Multiplatform-first packaging for Android and Desktop JVM.
- Two integration paths in one library: Compose APIs and Android View APIs.
- Better platform defaults via
Auto: long press on Android, right click on Desktop. - Production-focused publish shape:
radialmenu,radialmenu-android, andradialmenu-desktop. - Lean dependency surface in published metadata (
kotlin-stdlibonly).
KeyboardHoldis Compose-only;RadialMenuViewsupportsLongPressandSecondaryClick.- Best UX is typically
4-8items; more is supported but less ergonomic on small touch screens. - Desktop target is Compose Desktop JVM (Java 17+), not Swing/JavaFX-native widgets.
- If you use
Painterconstructors directly in View-only modules, addandroidx.compose.ui:ui(or useiconRes/Drawableoverloads).
- Website: gawwr4v.github.io/RadialMenu
- Getting Started: docs/getting-started.md
- Customization: docs/customization.md
- Compatibility: docs/compatibility.md
- Troubleshooting: docs/troubleshooting.md
- Changelog: CHANGELOG.md
- Discussions: GitHub Discussions
- Issues: GitHub Issues
- Contributing: CONTRIBUTING.md
Apache License 2.0. See LICENSE.
Developers often discover RadialMenu through searches like:
- Android radial menu
- Kotlin Multiplatform radial menu
- Compose Multiplatform circular menu
- Android pie menu
- Desktop pie menu
- KMP context menu
- Jetpack Compose radial menu

