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
- Writing @Composable functions
- The declarative UI mindset
- Text and Button composables
- Stacking UI with Column and Row
- Hosting composables with setContent
- Previewing UI with @Preview
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)
- Forgetting @Composable — Calling Text(...) from a plain function won't compile. Annotate the caller with @Composable.
- Lowercase composable name — It compiles, but breaks convention and the IDE may warn. Name UI-emitting composables like types: Greeting, not greeting.
- Using setContentView — For Compose use setContent { ... }, not the old XML inflation call.
- @Preview with parameters — A @Preview composable must take no parameters; wrap your real composable in a parameterless preview.
Pro Tips
- 💡 Small composables compose: break screens into tiny reusable composables — they're cheap to call.
- 💡 Preview early and often: a parameterless @Preview gives instant visual feedback without running the app.
- 💡 Think in state: describe what the UI looks like, and let Compose handle redrawing.
📋 Quick Reference — Compose Basics
| Concept | Kotlin / Compose |
|---|---|
| Composable | @Composable fun Greeting() { ... } |
| Text | Text("Hello") |
| Button | Button(onClick = { }) { Text("Go") } |
| Vertical stack | Column { ... } |
| Horizontal stack | Row { ... } |
| Host / preview | setContent { } • @Preview |
🎉 Lesson Complete!
- ✅ @Composable functions emit declarative UI
- ✅ Text and Button are core composables
- ✅ Column stacks vertically; Row horizontally
- ✅ setContent hosts composables in an Activity
- ✅ @Preview renders UI in the IDE
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
- Previous: Capstone: A CLI App
- Next: State & Recomposition in Compose — remember, mutableStateOf, state hoisting and recomposition
- Quick reference: Kotlin cheat sheet
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.