Jetpack Compose Basics

Reviewed & published by Brayan K

Jetpack Compose is Android's modern, declarative UI toolkit. Instead of inflating XML and poking at views, you write Kotlin functions that describe what the screen should look like.

Part of the free Kotlin course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.

By the end of this lesson you'll write @Composable functions, combine Text, Button, Column and Row, host them with setContent, and preview them in the IDE.

What You'll Learn in This Lesson

1️⃣ Your First Composable

A composable is a function marked with @Composable. It emits UI by calling other composables such as Text. Composables are named like types — starting with an uppercase letter.

import androidx.compose.material3.Text
import androidx.compose.runtime.Composable

// A @Composable function describes a piece of UI.
// By convention its name starts with an uppercase letter.
@Composable
fun Greeting(name: String) {
    Text(text = "Hello, $name!")
}

// Composables call OTHER composables to build the screen.
@Composable
fun WelcomeScreen() {
    Greeting(name = "Ada")
}

Notice there's no XML and no findViewById. The function is the UI: call it and it draws.

2️⃣ Laying Out with Column and Row

Column stacks children vertically; Row places them horizontally. Button takes an onClick lambda and its own composable content.

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable

@Composable
fun ProfileCard() {
    // Column stacks children vertically.
    Column {
        Text(text = "Ada Lovelace")
        Text(text = "Mathematician")

        // Row places children side by side.
        Row {
            Button(onClick = { /* follow */ }) {
                Text("Follow")
            }
            Button(onClick = { /* message */ }) {
                Text("Message")
            }
        }
    }
}

You nest composables to build structure: a Column containing two Text elements and a Row of buttons.

3️⃣ Hosting and Previewing

setContent inside an Activity's onCreate hosts your composables. @Preview renders a composable in Android Studio without launching the app.

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // setContent hosts your composables inside the Activity.
        setContent {
            Greeting("World")
        }
    }
}

@Composable
fun Greeting(name: String) {
    Text("Hello, $name!")
}

// @Preview renders the composable in Android Studio's design pane.
@Preview
@Composable
fun GreetingPreview() {
    Greeting("Preview")
}

Your turn. Replace the TODO, then preview and compare.

// 🎯 YOUR TURN — replace the TODO then preview it.

import androidx.compose.foundation.layout.Column
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable

@Composable
fun TodoList() {
    Column {
        // 1) Emit a heading. 👉 replace TODO with: Text("My Tasks")
        TODO

        Text("- Learn Compose")
        Text("- Build a screen")
    }
}

Mini-Challenge: A Business Card

Build a small composable that stacks a few Text elements in a Column, then preview it.

// 🎯 MINI-CHALLENGE: a tiny business card.
//
// 1. Write a @Composable function named BusinessCard().
// 2. Use a Column to stack three Text composables:
//    a name, a job title, and an email address.
// 3. Add a @Preview composable that calls BusinessCard().
//
// ✅ Example rendered output (top to bottom):
//    Grace Hopper
//    Computer Scientist
//    grace@navy.mil

@Composable
fun BusinessCard() {
    // your code here
}

Common Errors (and the fix)

Pro Tips

📋 Quick Reference — Compose Basics

ConceptKotlin / Compose
Composable@Composable fun Greeting() { ... }
TextText("Hello")
ButtonButton(onClick = { }) { Text("Go") }
Vertical stackColumn { ... }
Horizontal stackRow { ... }
Host / previewsetContent { } • @Preview

🎉 Lesson Complete!

Practice quiz

What annotation marks a function as a Compose UI building block?

  • @Compose
  • @Composable
  • @UI
  • @View

Answer: @Composable. @Composable marks a function that emits UI in Jetpack Compose.

Jetpack Compose follows which UI paradigm?

  • Declarative
  • Imperative XML inflation
  • Retained-mode only
  • Immediate-mode canvas only

Answer: Declarative. Compose is declarative: you describe the UI for a given state and the framework draws it.

Which composable displays a string of text?

  • Label(...)
  • TextView(...)
  • Text(...)
  • Print(...)

Answer: Text(...). Text("...") is the built-in composable for showing text.

Which layout composable stacks children vertically?

  • Row
  • Stack
  • VBox
  • Column

Answer: Column. Column arranges its children top to bottom; Row arranges them left to right.

How does an Activity set its Compose content?

  • setContentView(R.layout.main)
  • setContent { ... }
  • inflate(...)
  • attachCompose()

Answer: setContent { ... }. setContent { } inside onCreate hosts composables in an Activity.

What annotation lets you render a composable in the IDE design pane without running the app?

  • @Preview
  • @Render
  • @Design
  • @Mock

Answer: @Preview. @Preview on a parameterless composable shows it in Android Studio's preview pane.

Which composable arranges children horizontally?

  • Column
  • Pile
  • Row
  • Grid

Answer: Row. Row lays out its children in a horizontal line.

A composable function's name conventionally starts with what?

  • a lowercase letter
  • an underscore
  • the prefix 'fun'
  • an uppercase letter

Answer: an uppercase letter. By convention composables are named like types, starting with an uppercase letter (e.g. Greeting).

What does a @Composable function typically return?

  • Unit (it emits UI rather than returning a value)
  • A View object
  • An XML string
  • A Bitmap

Answer: Unit (it emits UI rather than returning a value). Most composables return Unit; they describe UI by calling other composables, not by returning a value.

Why must a @Composable function be called from another @Composable?

  • For performance only
  • It is a style preference
  • Compose tracks calls in a composition, so the call site must itself be composable
  • To avoid imports

Answer: Compose tracks calls in a composition, so the call site must itself be composable. Composables run inside a composition; only another composable provides that context.

Continue this course

Frequently asked questions

What makes a function 'composable'?

Adding the @Composable annotation. That annotation tells the Compose compiler the function participates in a composition — it emits UI by calling other composables rather than returning a View. Composables can only be called from other composables (or from an entry point like setContent), because Compose needs the surrounding composition to track and update what is drawn.

How is declarative UI different from the old XML approach?

With XML layouts you describe a static tree and then imperatively mutate it (findViewById, setText, setVisibility). In Compose you write a function that describes what the UI should look like for the current state. When the state changes, Compose re-runs the relevant functions and updates the screen for you. You describe the 'what', not the step-by-step 'how'.

Why do composable names start with a capital letter?

It is a strong naming convention, not a hard language rule. Composables that emit UI are named like types — Greeting, ProfileCard, BusinessCard — so they read like UI elements at the call site. Composables that instead return a value (helpers) follow normal function naming. The convention makes call sites easy to scan.

What does setContent do?

setContent is the bridge between the classic Android Activity world and Compose. Called inside onCreate, it tells the Activity to host the composables in its trailing lambda as the screen's content, replacing the older setContentView(R.layout.xxx). Everything inside that lambda is a composable, so this is where your top-level screen composable goes.