EmergeTools logo
🙏 Supported by Emerge Tools
The platform for all your mobile performance needs

Compare Declarative Frameworks

Choose up-to 3 frameworks and learn how they compare to each other.
Framework Logo
Framework Logo
Framework Logo
Framework Logo
Framework Logo
Creating a new Component
Components are the reusable building blocks of your application. They are the most basic UI elements and can be used to build more complex components.
Jetpack Compose
kotlin
@Composable
fun MyComponent(
    displayString: String
) {
    Text(displayString)
}
SwiftUI
swift
struct MyComponent: View {
    var displayString: String
    var body: some View {
        Text(displayString)
    }
}
Vue.js
javascript
<template>
  <div>{{ displayString }}</div>
</template>

<script setup>
import { defineProps } from 'vue';

const props = defineProps({
  displayString: String
});
</script>
Conditional Rendering
Conditional rendering is a technique used to display different UI components or content based on certain conditions, such as the value of a variable or the outcome of a boolean expression.
Jetpack Compose
kotlin
@Composable
fun ConditionalComponent(condition: Boolean) {
    if (condition) {
        Text("Condition is true")
    } else {
        Text("Condition is false")
    }
}

// Usage
ConditionalComponent(condition = true)
SwiftUI
swift
struct ConditionalComponent: View {
    let condition: Bool

    var body: some View {
        Group {
            if condition {
                Text("Condition is true")
            } else {
                Text("Condition is false")
            }
        }
    }
}

// Usage
ConditionalComponent(condition: true)
Vue.js
javascript
<template>
  <p v-if="condition">Condition is true</p>
  <p v-else>Condition is false</p>
</template>

<script setup>
import { defineProps } from 'vue';

const props = defineProps({
  condition: Boolean
});
</script>
Prop/Parameter Drilling
Prop/Parameter drilling is a technique where data is passed through multiple layers of components in the component hierarchy, often from a parent component to a deeply nested child component, via props or parameters.
Jetpack Compose
kotlin
@Composable
fun Parent(data: String) {
    IntermediateComponent(data = data)
}

@Composable
fun IntermediateComponent(data: String) {
    ChildComponent(data = data)
}

@Composable
fun ChildComponent(data: String) {
    Text("Received data: $data")
}

// Usage
Parent(data = "Some data")
SwiftUI
swift
struct Parent: View {
    let data: String

    var body: some View {
        IntermediateComponent(data: data)
    }
}

struct IntermediateComponent: View {
    let data: String

    var body: some View {
        ChildComponent(data: data)
    }
}

struct ChildComponent: View {
    let data: String

    var body: some View {
        Text("Received data: \(data)")
    }
}

// Usage
Parent(data: "Some data")
Vue.js
javascript
<template>
  <intermediate-component :data="data" />
</template>

<script setup>
import { defineProps } from 'vue';
import IntermediateComponent from './IntermediateComponent.vue';

const props = defineProps({
  data: String
});
</script>
Responding to events
Responding to events involves handling user interactions, such as button clicks or text input changes, and updating the component's state or triggering side effects accordingly.
Jetpack Compose
kotlin
@Composable
fun ClickableComponent() {
    var clicked by remember { mutableStateOf(false) }

    Button(onClick = { clicked = true }) {
        Text(if (clicked) "Button clicked" else "Click me")
    }
}
SwiftUI
swift
struct ClickableComponent: View {
    @State private var clicked = false

    var body: some View {
        Button(action: {
            clicked = true
        }) {
            Text(clicked ? "Button clicked" : "Click me")
        }
    }
}
Vue.js
javascript
<template>
  <button @click="setClicked">
    {{ clicked ? "Button clicked" : "Click me" }}
  </button>
</template>

<script setup>
import { ref } from 'vue';

const clicked = ref(false);

function setClicked() {
  clicked.value = true;
}
</script>
Handing user input
Handling user input involves capturing and processing user interactions with input fields, such as text fields, sliders, or checkboxes, and updating the component's state or triggering side effects based on the input.
Jetpack Compose
kotlin
@Composable
fun TextInputComponent() {
    var text by remember { mutableStateOf("") }

    TextField(
        value = text,
        onValueChange = { newText -> text = newText },
        label = { Text("Enter text") }
    )
}
SwiftUI
swift
struct TextInputComponent: View {
    @State private var text = ""

    var body: some View {
        TextField("Enter text", text: $text)
    }
}
Vue.js
javascript
<template>
  <input
    type="text"
    v-model="text"
    placeholder="Enter text"
  />
</template>

<script setup>
import { ref } from 'vue';

const text = ref('');
</script>
Previewing a Component
Creating a preview of a component involves displaying a visual representation of the component in the development environment to help with the design and layout process.
Jetpack Compose
kotlin
@Composable
fun ExampleComponent() {
    Text("Hello, World!")
}

@Preview(showBackground = true)
@Composable
fun ExampleComponentPreview() {
    ExampleComponent()
}

Additionally, you can also use Showkase, an open source library by Airbnb that allows you to view themes preview functions in an auto-generated component browser that can be viewed on an Android device.

SwiftUI
swift
struct ExampleComponent: View {
    var body: some View {
        Text("Hello, World!")
    }
}

struct ExampleComponent_Previews: PreviewProvider {
    static var previews: some View {
        ExampleComponent()
    }
}
Vue.js

Vue.js doesn't have a built-in preview feature. However, you can use a tool like Storybook to create previews for your components in a separate development environment.

Lists & Looping
Lists and looping involve rendering a dynamic number of components based on the length of a list or array, iterating over the list, and generating a UI component for each item.
Jetpack Compose
kotlin
@Composable
fun ListComponent(items: List<String>) {
    LazyColumn {
        items(items) { item ->
            Text(item)
        }
    }
}

// Usage
val items = listOf("Item 1", "Item 2", "Item 3")
ListComponent(items = items)
SwiftUI
swift
struct ListComponent: View {
    let items: [String]

    var body: some View {
        List(items, id: \.self) { item in
            Text(item)
        }
    }
}

// Usage
let items = ["Item 1", "Item 2", "Item 3"]
ListComponent(items: items)
Vue.js
javascript
<template>
  <ul>
    <li v-for="item in items" :key="item">
      {{ item }}
    </li>
  </ul>
</template>

<script setup>
import { defineProps } from 'vue';

const props = defineProps({
  items: Array
});
</script>

<!-- Usage -->
<list-component :items="['Item 1', 'Item 2', 'Item 3']"></list-component>
List item keys
List Item Keys are unique identifiers assigned to each list item in declarative UI frameworks to help manage and update list elements efficiently. Using List Item Keys enables the framework to optimize the rendering process, minimizing unnecessary updates and improving overall performance.
Jetpack Compose
kotlin
data class Person(val name: String, val age: Int, val id: String)

@Composable
fun ItemKeysExample(items: List<Person>) {
    LazyColumn {
        items(items, key = { person -> person.id }) { person ->
            Text("Name: ${person.name}, Age: ${person.age}")
        }
    }
}
SwiftUI
swift
struct Person: Identifiable {
    let name: String
    let age: Int
    let id: String
}

struct ItemKeysExample: View {
    let items: [Person]

    var body: some View {
        List(items) { person in
            Text("Name: \(person.name), Age: \(person.age)")
        }
    }
}

// Usage
ItemKeysExample(items: [Person(name: "John", age: 30, id: "1"), Person(name: "Jane", age: 28, id: "2"), Person(name: "Bob", age: 25, id: "3")])
Vue.js
javascript
<template>
  <ul>
    <li v-for="person in items" :key="person.id">
      Name: {{ person.name }}, Age: {{ person.age }}
    </li>
  </ul>
</template>

<script setup>
import { defineProps } from 'vue';

const props = defineProps({
  items: Array
});
</script>

<!-- Usage -->
<item-keys-example
  :items="[
    { name: 'John', age: 30, id: '1' },
    { name: 'Jane', age: 28, id: '2' },
    { name: 'Bob', age: 25, id: '3' }
  ]"
></item-keys-example>
Slot APIs
Slot APIs refer to a technique where components have customizable parts or 'slots' that can be filled with content when the component is being used. This allows for greater reusability and flexibility in composing user interfaces. The content that fills these slots can be other components or simple UI elements like text or images.
Jetpack Compose
kotlin
@Composable
fun Parent(
    header: @Composable () -> Unit,
    content: @Composable () -> Unit
) {
    Column {
        header()
        content()
    }
}

// Usage
Parent(
    header = { Text("Header") },
    content = { Child() }
)

@Composable
fun Child() {
    Text("Child Content")
}
SwiftUI
swift
struct Parent<Header: View, Content: View>: View {
    let header: Header
    let content: Content

    var body: some View {
        VStack {
            header
            content
        }
    }
}

// Usage
Parent(
    header: Text("Header"),
    content: Child()
)

struct Child: View {
    var body: some View {
        Text("Child Content")
    }
}
Vue.js
javascript
// ParentComponent.vue
<template>
  <div>
    <slot name="header"></slot>
    <slot name="content"></slot>
  </div>
</template>

// ChildComponent.vue
<template>
  <p>Child Content</p>
</template>

// Usage
<parent-component>
  <template v-slot:header>
    <h1>Header</h1>
  </template>
  <template v-slot:content>
    <child />
  </template>
</parent-component>
Modifiers
Modifiers are used to adjust or configure the UI elements' appearance or behavior in a declarative UI framework.
Jetpack Compose
kotlin
@Composable
fun ModifiersExample() {
    Text(
        "Hello, World!",
        modifier = Modifier
            .padding(16.dp)
            .background(Color.Blue)
    )
}
SwiftUI
swift
struct ModifiersExample: View {
    var body: some View {
        Text("Hello, World!")
            .padding(EdgeInsets(top: 16, leading: 16, bottom: 16, trailing: 16))
            .background(Color.blue)
    }
}
Vue.js

Vue.js doesn't have a direct analog to modifiers in Jetpack Compose or SwiftUI. Instead, you can use inline styles or CSS classes.

javascript
<template>
  <div :style="style">Hello, World!</div>
</template>

<script setup>
import { reactive } from 'vue';

const style = reactive({
  padding: '16px',
  backgroundColor: 'blue',
  color: 'white'
});
</script>
State
State management refers to the process of handling and updating the internal state of components, often in response to user interactions or other events.
Jetpack Compose
kotlin
@Composable
fun Counter() {
    var count by remember { mutableStateOf(0) }

    Button(onClick = { count = count + 1 }) {
        Text("Count: $count")
    }
}
SwiftUI
swift
struct Counter: View {
    @State private var count = 0

    var body: some View {
        Button(action: {
            count += 1
        }) {
            Text("Count: \(count)")
        }
    }
}
Vue.js
javascript
<template>
  <button @click="incrementCount">
    Count: {{ count }}
  </button>
</template>

<script setup>
import { ref } from 'vue';

const count = ref(0);

function incrementCount() {
  count.value++;
}
</script>
Scoped Data Propagation
Scoped Data Propagation is a technique that involves passing data across multiple levels of a component subtree without having to explicitly pass it through every intermediate component. It helps reduce the complexity of prop drilling and allows for a more efficient way of sharing data in a specific scope.
Jetpack Compose
kotlin
val CustomLocal = compositionLocalOf<String> { "Default data" }

@Composable
fun Parent(data: String) {
    CompositionLocalProvider(CustomLocal provides data) {
        Intermediate()
    }
}

@Composable
fun Intermediate() {
    Child()
}

@Composable
fun Child() {
    val data = CustomLocal.current
    Text("Received data: $data")
}

// Usage
Parent(data = "Some data")
SwiftUI
swift
struct CustomEnvironmentKey: EnvironmentKey {
    static let defaultValue: String = ""
}

extension EnvironmentValues {
    var customData: String {
        get { self[CustomEnvironmentKey.self] }
        set { self[CustomEnvironmentKey.self] = newValue }
    }
}

struct Parent: View {
    let data: String

    var body: some View {
        Intermediate().environment(\.customData, data)
    }
}

struct Intermediate: View {
    var body: some View {
        Child()
    }
}

struct Child: View {
    @Environment(\.customData) private var data

    var body: some View {
        Text("Received data: \(data)")
    }
}

// Usage
Parent(data: "Some data")
Vue.js
javascript
<!-- ParentComponent.vue -->
<template>
  <intermediate />
</template>

<script setup>
import { provide, ref } from 'vue';
import Intermediate from './IntermediateComponent.vue';

const data = ref('Some data');
provide('dataKey', data);
</script>

<!-- IntermediateComponent.vue -->
<template>
  <child />
</template>

<script setup>
import Child from './ChildComponent.vue';
</script>

<!-- ChildComponent.vue -->
<template>
  <p>Received data: {{ data }}</p>
</template>

<script setup>
import { inject } from 'vue';

const data = inject('dataKey');
</script>


<!-- Usage -->
<parent-component data="Some data"></parent-component>
Side Effects
A side effect involves executing code that can have external consequences or perform operations that are not directly related to rendering the UI, such as making network requests or updating external data sources.
Jetpack Compose
kotlin
@Composable
fun SideEffectOnLoadComponent() {
    LaunchedEffect(Unit) {
        // Perform side effect, e.g. fetch data, update external data source
    }

    // Other UI components
    Text("Hello, World!")
}
SwiftUI
swift
struct SideEffectOnLoadComponent: View {
    @State private var hasPerformedSideEffect = false

    var body: some View {
        if !hasPerformedSideEffect {
            DispatchQueue.main.async {
                // Perform side effect, e.g. fetch data, update external data source
                hasPerformedSideEffect = true
            }
        }

        // Other UI components
        Text("Hello, World!")
    }
}
Vue.js
javascript
<template>
  <div></div>
</template>

<script setup>
import { onMounted } from 'vue';

onMounted(() => {
  // Perform side effect here
});
</script>