A Compose Multiplatform adaptation of the native macos 26 style. This port brings the same design language to Android, iOS, Desktop, and Web through Compose Multiplatform.
- 30+ components — Buttons, Cards, Dialogs, Tables, Toasts, and more
- Light & Dark mode — Theme-aware styling with automatic system detection
- macOS aesthetic — Clean, native-feeling design inspired by Apple's design language
- Compose Multiplatform — Runs on Android, iOS, Desktop (JVM), and Web (JS/Wasm)
- Decorated window — Full-size content window with native traffic lights and glass materials on desktop
- Built-in design system — Colors, typography (Manrope), shapes, and animations out of the box
- No external UI dependencies — Pure Compose, no Material dependency required
| Platform | Status |
|---|---|
| Android | ✓ |
| iOS | ✓ |
| Desktop (JVM) | ✓ |
| Web (JS) | ✓ |
| Web (Wasm) | ✓ |
| Artifact | Contents |
|---|---|
dev.nucleusframework:compose-macos-ui |
Components, theme, decorated window |
dev.nucleusframework:compose-macos-ui-icons |
Core icon set (already exposed by compose-macos-ui) |
dev.nucleusframework:compose-macos-ui-icons-extended |
Full icon set |
dev.nucleusframework:compose-macos-ui-markdown |
macOS-styled Markdown renderer |
// build.gradle.kts
kotlin {
sourceSets {
commonMain.dependencies {
implementation("dev.nucleusframework:compose-macos-ui:<version>")
}
}
}import dev.nucleusframework.macoscompose.theme.MacosTheme
@Composable
fun App() {
MacosTheme(darkTheme = false) {
// Your content here
// Access design tokens via MacosTheme.colorScheme, MacosTheme.typography, etc.
}
}MacosTheme also accepts accentColor (blue, purple, violet, green, orange, red, yellow, cyan, pink,
teal, emerald, sky), liquidGlass, glassType, and full overrides for colorScheme, typography,
shapes, animations, and componentStyling.
import dev.nucleusframework.macoscompose.components.*
@Composable
fun MyApp() {
var selectedItem by remember { mutableStateOf("Inbox") }
Scaffold(
sidebar = {
Sidebar(
items = listOf(
SidebarItem("Home", onClick = { selectedItem = "Home" }, icon = LucideHome),
SidebarItem("Favorites", onClick = { selectedItem = "Favorites" }, icon = LucideStar),
SidebarItem("Settings", onClick = { selectedItem = "Settings" }, icon = LucideSettings),
),
activeItem = selectedItem,
)
},
titleBar = {
TitleBar(
title = { Text("Mail") },
actions = {
IconButton(
icon = Icons.Share2,
onClick = { /* ... */ },
style = IconButtonStyle.Borderless,
)
},
)
},
) { padding ->
Column(Modifier.padding(padding).padding(16.dp)) {
Text("Welcome to macOS UI", style = MacosTheme.typography.title1)
PushButton(onClick = { /* ... */ }) {
Text("Get Started")
}
}
}
}Icons go through SystemIcon, which pairs a native SF Symbol name with a Lucide fallback:
data class SystemIcon(val sfSymbolName: String, val fallback: ImageVector)
// dev.nucleusframework.macoscompose.icons.Icons
val Home = SystemIcon("house", LucideHome)
val Settings = SystemIcon("gearshape", LucideSettings)On macOS the SF Symbol is loaded natively through AppKit; every other platform draws the Lucide
vector. Prefer Icons.* over raw Lucide vectors so Apple platforms get the native glyph:
IconButton(icon = Icons.Share2, onClick = { /* ... */ }) // SF Symbol on macOS, Lucide elsewhere
IconButton(icon = LucideShare2, onClick = { /* ... */ }) // Lucide everywhereSidebarItem.icon currently takes an ImageVector, so sidebar items always render the Lucide
vector even on macOS. Use Icons.* everywhere else.
compose-macos-ui-icons-extended adds the full icon set for icons not covered by Icons.
On desktop, macOS chrome is not something Compose can draw on its own: the traffic lights, the
window corner radius and the sidebar glass material are native surfaces. MacosDecoratedWindow
wraps Nucleus' DecoratedWindow (Tao backend — no AWT, no
bundled JNI) and reproduces SwiftUI's full-size content window:
- The window is
fullSizeContentViewwith a transparent title bar, so Compose content fills the entire frame. - A hidden
NSToolbaris installed to get the macOS 26 large corner radius. - Traffic lights are recentered natively against
titleBarHeight. On Windows and Linux the window is fully undecorated and the platform window controls are drawn in that same band. - Native surfaces (materials, traffic lights, window background) follow
MacosThemerather than the OS appearance — a dark app on a light system still gets a dark sidebar material. Scaffold's sidebar extends to the top of the window with the traffic lights floating over its header, likeNavigationSplitView.
The desktop entry point runs inside nucleusApplication, which needs the Nucleus Gradle plugin.
It also patches the JVM for the macOS 26.0 SDK (Liquid Glass) when you run.
// build.gradle.kts
plugins {
alias(libs.plugins.kotlinMultiplatform)
alias(libs.plugins.composeMultiplatform)
alias(libs.plugins.composeCompiler)
id("dev.nucleusframework") version "<nucleus-version>"
}
nucleus.application {
mainClass = "com.example.app.MainKt"
nativeDistributions {
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
packageName = "com.example.app"
packageVersion = "1.0.0"
}
}compose-macos-ui already exposes nucleus.decorated-window-tao and nucleus.nucleus-application
as api dependencies on the JVM target, so no extra runtime dependency is required.
import dev.nucleusframework.application.nucleusApplication
import dev.nucleusframework.macoscompose.window.MacosDecoratedWindow
fun main() = nucleusApplication {
MacosDecoratedWindow(
onCloseRequest = ::exitApplication,
title = "My App",
) {
App() // MacosTheme lives inside the window content
}
}MacosTheme must be inside the window content: the window sits above the theme and receives the
resolved appearance from it, which is what keeps the native surfaces in sync.
| Parameter | Default | Description |
|---|---|---|
onCloseRequest |
— | Invoked when the user closes the window |
state |
rememberWindowState() |
Position, size and maximized/minimized state |
visible |
true |
Window visibility |
title |
"" |
Window title (shown in the Dock / taskbar) |
icon |
null |
Window icon Painter |
resizable |
true |
When false, the maximize button is dropped |
enabled |
true |
Whether the window accepts input |
focusable |
true |
Whether the window can take focus |
alwaysOnTop |
false |
Keep the window above others |
hiddenFromDock |
false |
Hide from the Dock/taskbar while staying visible and focusable (Linux: X11/XWayland only) |
minimumSize |
null |
Minimum DpSize |
onPreviewKeyEvent / onKeyEvent |
{ false } |
Window-level key handling |
titleBarHeight |
52.dp |
Height of the native title bar band; match it to your TitleBarStyle |
The content lambda is a NucleusDecoratedWindowScope, so it can reach the window state and the
Nucleus chrome APIs (WindowBackdrop, WindowAppearance, …).
titleBarHeight drives the native layer (traffic-light centering, Windows caption zone) while the
visible toolbar is drawn by Scaffold/TitleBar. Keep the two in agreement:
MacosDecoratedWindow(
onCloseRequest = ::exitApplication,
titleBarHeight = TitleBarStyle.Unified.height.dp,
) { /* ... */ }| macOS | Windows | Linux | |
|---|---|---|---|
| Traffic lights | Native AppKit, recentered | Compose-drawn WindowControls (trailing) |
Compose-drawn WindowControls (trailing) |
| Corner radius | macOS 26 large radius (hidden NSToolbar) |
Platform default | Platform default |
| Sidebar material | Native window glass region | Compose-drawn fallback | Compose-drawn fallback |
For the full component catalog, API details, and interactive demos, visit the documentation.
The sample doubles as a gallery. Native installers are built with GraalVM and attached to every
v* tag by the Release Gallery workflow — grab them from
the releases page.
To build one locally (the Nucleus plugin downloads the GraalVM 25 JDK itself):
./gradlew :sample:packageGraalvmDmg # macOS
./gradlew :sample:packageGraalvmNsis # Windows
./gradlew :sample:packageGraalvmDeb # Linux./gradlew :sample:run # desktop sample
./gradlew :sample:jsBrowserDevelopmentRun # web (JS)
./gradlew :sample:wasmJsBrowserDevelopmentRun # web (Wasm)
./gradlew detekt # static analysis, required before committingNew components need a matching page in sample/.../pages/ annotated with @GalleryEntry.
Compose Macos UI is available under the MIT License.