Hey everyone! I'm Daniel, the developer behind compose-svelted, an experimental UI framework that brings the Jetpack Compose development experience to Svelte and the web. Today I want to share the journey, philosophy, and technical decisions behind this project.
The Problem: Why I Built This
As an Android developer who's worked extensively with Jetpack Compose, I fell in love with its declarative, predictable approach to building UIs. When I started exploring web development, I found myself constantly frustrated by CSS's implicit behaviors, global side effects, and the general unpredictability of traditional web layout systems.
I kept thinking: "What if we could bring Compose's mental model to the web?" Not just as another Material Design component library, but as a fundamental shift in how we think about web UI composition.
The Vision: Compose Philosophy on the Web
compose-svelted isn't about copying Compose line-for-line. It's about capturing the core principles that make Compose such a productive framework:
1. UI as a Function of State
Every component in compose-svelted is a pure function of its state. No hidden side effects, no mysterious context propagation you can't trace.
2. Immutable, Chainable Modifiers
Instead of writing CSS rules that might conflict or have unexpected cascading effects, you describe your UI's appearance through immutable modifiers:
<Column
modifier={Modifier
.fillMaxWidth()
.padding(16)
.background(Theme.colors.surface)
.clip(RoundedCornerShape(8))}
>
<Text text="Hello Compose-Svelted!" />
</Column>
3. Layout as Composition, Not Magic
Traditional CSS often feels like a black box. compose-svelted makes layout explicit and predictable. Column, Row, and Box components behave exactly as you'd expect from their Compose counterparts.
4. Navigation as State
Why should navigation be this separate, router-driven concern? In compose-svelted, navigation is just another piece of state you manage:
const navController = useNavController();
// Navigate to a screen
navController.navigateTo("profile");
// Handle back navigation naturally
navController.popBackStack();
Technical Architecture: Why Svelte?
You might be wondering: "Why build this on Svelte instead of React or Solid?"
The answer is in Svelte's compiler-based approach. Like Compose, Svelte eliminates the virtual DOM overhead and provides fine-grained reactivity. This creates a natural alignment with Compose's philosophy of predictable, efficient UI updates.
What compose-svelted adds to Svelte:
- A Compose-inspired component API
- Immutable modifier system
- Structural motion animations
- Declarative navigation system
- Theme system with Material-like tokens
Current Status: Alpha but Ambitious
We're currently in Alpha, but here's what's already working:
✅ Core V1 - Complete
- Layout components (
Column,Row,Box) - Immutable modifier system
- Shape system (
RectangleShape,RoundedCornerShape,CircleShape) - Theme system with color, typography, and elevation tokens
- Basic components (
Text,TextField,Button)
✅ Core V2 - Complete
- Structural motion (
AnimatedVisibility,AnimatedContent) - Declarative animations
- Navigation system (
NavController,NavHost,backstackmanagement) - Cross-fade and slide transitions
🚧 Core V3 - In Planning
- Nested navigation graphs
- Directional transitions (slide in/out based on navigation direction)
- Shared element transitions
- More advanced gesture support
The Innovation: What Makes This Different
- No Virtual DOM Abstraction: We work with Svelte's reactivity, not against it
- Motion as Structure: Animations aren't afterthoughts—they're part of your component's structure
- No Global CSS Side Effects: Everything is scoped and predictable
- Perfect for Android Devs Learning Web: The learning curve becomes a gentle slope instead of a wall
Challenges and Lessons
Building this hasn't been easy. Some of the biggest challenges:
- Mapping Compose Concepts to Web: Some Compose features don't have direct web equivalents
- Performance with Modifiers: Ensuring our modifier chain doesn't create unnecessary re-renders
- Bundle Size: Keeping it lean while providing meaningful functionality
- Documentation: Making it accessible to both web and Android developers
Example: Building a Simple Card
Here's what it looks like to build a card component:
<script lang="ts">
import { Column, Text, Button, Modifier, RoundedCornerShape } from 'compose-svelted';
import { Theme } from 'compose-svelted/theme';
export let title: string;
export let description: string;
export let onAction: () => void;
</script>
<Column
modifier={Modifier
.fillMaxWidth()
.padding(24)
.background(Theme.colors.surface)
.clip(RoundedCornerShape(8))
.elevation(2)}
>
<Text
text={title}
style={Theme.typography.h6}
modifier={Modifier.padding(bottom=8)}
/>
<Text
text={description}
style={Theme.typography.body1}
modifier={Modifier.padding(bottom=16)}
/>
<Button
text="Learn More"
onClick={onAction}
modifier={Modifier.align(horizontal="end")}
/>
</Column>
Try It Out!
The project is open source on GitHub, and I'd love for you to try it:
npm create compose-svelted@latest
Or check out the examples in the repository to see more complex implementations.
Looking Forward
This project is my attempt to bridge two worlds I love: Android's modern UI development and the web's ubiquity. Whether you're an Android developer curious about the web, or a web developer interested in declarative UI patterns, I hope compose-svelted provides a fresh perspective.
I'm particularly looking for:
- Feedback from Android developers trying web development
- Contributions to expand the component set
- Real-world use cases to guide development
- Help with documentation and examples
Have you tried bringing patterns from one platform to another? What challenges did you face? I'd love to hear your thoughts and experiences in the comments!
Compose-svelted is an experimental project. APIs may change as we learn what works best for the web platform. MIT Licensed.
Top comments (0)