Question
How to Get Context in Jetpack Compose for Toast Messages in Kotlin
Question
I am using Jetpack Compose and want to show a Toast message when a button is clicked inside a composable item. In the older View-based approach, I would normally pass an Activity or Context, but I am not sure how to access it inside a composable.
Here is the code:
fun createListItem(itemIndex: Int) {
Padding(left = 8.dp, right = 8.dp, top = 8.dp, bottom = 8.dp) {
FlexRow(crossAxisAlignment = CrossAxisAlignment.Center) {
expanded(1.0f) {
Text("Item $itemIndex")
}
inflexible {
Button(
text = "Button $itemIndex",
style = ContainedButtonStyle(),
onClick = {
Toast.makeText(
this@MainActivity,
"Item name $itemIndex",
Toast.LENGTH_SHORT
).show()
}
)
}
}
}
}
How do I correctly get a Context in Jetpack Compose so I can pass it to Toast.makeText()?
Short Answer
By the end of this page, you will understand how Context works in Jetpack Compose, why this@MainActivity is usually not the right approach inside a composable, and how to use LocalContext.current to show a Toast safely and cleanly.
Concept
In Android, many APIs need a Context. A Toast is one of them. In the traditional View system, you often had direct access to an Activity, Fragment, or View, so getting a Context felt straightforward.
In Jetpack Compose, UI is written as composable functions. These functions are not class instances like Activity, so this usually does not refer to what you expect. That is why code such as this@MainActivity is often not available or not appropriate inside a composable.
Compose provides access to Android framework objects through Composition Locals. For Context, the standard way is:
val context = LocalContext.current
This gives you the current Android Context for the composable tree. You can then use it with APIs like:
Toast.makeText(...)- reading resources
- accessing system services
- starting activities in some cases
Why this matters:
- It keeps composables decoupled from a specific
Activity - It works naturally inside Compose UI code
- It makes your code easier to reuse and test
A good rule is: if Android API code needs a Context inside a composable, reach for LocalContext.current first.
Mental Model
Think of Context as your app's environment pass.
In the old View system, you were often standing inside a room that already had a label like MainActivity, so grabbing the environment was easy.
In Compose, a composable is more like a recipe for UI, not a room itself. Since the recipe is not the activity, it does not automatically have direct access to MainActivity.
LocalContext.current is like asking the Compose system:
“What Android environment am I currently running in?”
Compose then hands you the right Context for that part of the UI tree.
Syntax and Examples
The basic Compose syntax is:
val context = LocalContext.current
Then use it in your click handler:
Toast.makeText(context, "Hello", Toast.LENGTH_SHORT).show()
Example
@Composable
fun CreateListItem(itemIndex: Int) {
val context = LocalContext.current
Row(modifier = Modifier.padding(8.dp)) {
Text(
text = "Item $itemIndex",
modifier = Modifier.weight(1f)
)
Button(
onClick = {
Toast.makeText(
context,
"Item name $itemIndex",
Toast.LENGTH_SHORT
).show()
}
) {
Text("Button $itemIndex")
}
}
}
Why this works
LocalContext.currentgives the current AndroidContext- The
contextvalue can be used inside the button'sonClick - The composable stays reusable because it does not depend directly on
MainActivity
Import you usually need
import androidx.compose.ui.platform.LocalContext
If you are using modern Compose, this is the standard approach.
Step by Step Execution
Consider this composable:
@Composable
fun ToastButton(itemIndex: Int) {
val context = LocalContext.current
Button(onClick = {
Toast.makeText(context, "Clicked item $itemIndex", Toast.LENGTH_SHORT).show()
}) {
Text("Show Toast")
}
}
Here is what happens step by step:
- Compose starts building the UI for
ToastButton. val context = LocalContext.currentasks Compose for the current AndroidContext.- Compose stores that
contextvalue for this composition. - The
Buttonis displayed on screen. - The user taps the button.
- The
onClicklambda runs. Toast.makeText(context, "Clicked item $itemIndex", Toast.LENGTH_SHORT)creates a toast..show()displays the toast on screen.
Trace example
If itemIndex is 3, then:
- The text shown on the button is
Show Toast - On click, the toast message becomes
Clicked item 3
This is a simple pattern: get the context once inside the composable, then use it when needed.
Real World Use Cases
Getting Context in Compose is useful in many real apps, not just for Toast.
Common use cases
-
Showing toast messages
- Example: "Profile saved"
- Example: "Failed to load data"
-
Accessing resources
- Reading strings, dimensions, or other Android resources
-
Using Android services
- Clipboard
- Connectivity manager
- Notification manager
-
Starting Android components
- Launching another activity with an
Intent
- Launching another activity with an
-
Working with files or preferences
- Accessing app storage helpers that need a
Context
- Accessing app storage helpers that need a
Example scenario
In a shopping app:
- User taps Add to cart
- A toast says Item added to cart
- The composable uses
LocalContext.currentto create that toast
In a form screen:
- User presses Submit
- Validation fails
- A toast or Android service might need a
Context
Real Codebase Usage
In real projects, developers often use Context in Compose with a few common patterns.
1. Direct UI feedback
For quick feedback such as a toast:
val context = LocalContext.current
Button(onClick = {
Toast.makeText(context, "Saved", Toast.LENGTH_SHORT).show()
}) {
Text("Save")
}
2. Keep business logic out of composables
A composable should usually handle UI actions, while business logic stays in a ViewModel or use-case layer.
Good pattern:
- ViewModel decides what happened
- Composable decides how to display it
For example, a ViewModel emits a success event, and the composable shows a toast using context.
3. Guard clauses before using Context-based APIs
Example:
if (itemIndex < 0) return
This prevents invalid actions before trying to show a toast or start another Android action.
4. Event handling pattern
A common real-world pattern is:
- user clicks button
- UI sends event
- state updates
- composable reacts
- composable uses
LocalContext.currentfor Android-only UI work
5. Avoid passing Activity everywhere
Instead of tightly coupling composables to MainActivity, developers prefer using LocalContext.current or passing a callback.
This makes components:
- easier to reuse
- easier to preview
- less dependent on screen-specific classes
Common Mistakes
1. Using this@MainActivity inside a composable
Broken example:
@Composable
fun MyItem() {
Button(onClick = {
Toast.makeText(this@MainActivity, "Hello", Toast.LENGTH_SHORT).show()
}) {
Text("Click")
}
}
Why it is a problem:
- A composable is not the activity
thismay not refer to what you think- It tightly couples the composable to one activity
Use this instead:
@Composable
fun MyItem() {
val context = LocalContext.current
Button(onClick = {
Toast.makeText(context, "Hello", Toast.LENGTH_SHORT).show()
}) {
Text("Click")
}
}
2. Forgetting @Composable
Broken example:
fun MyItem() {
val context = LocalContext.current
}
Why it breaks:
LocalContext.currentcan only be read from a composable context
Fix:
@Composable
fun MyItem() {
val context = LocalContext.current
}
3. Putting too much Android logic directly in UI code
Avoid turning composables into large Android control centers.
Less ideal:
@Composable
fun MyScreen() {
val context = LocalContext.current
// many system calls, storage calls, service calls, navigation calls
}
Better:
- Keep UI in composables
- Move app logic to ViewModel or other layers
- Use
contextonly when the Android framework specifically requires it
4. Storing context in a long-lived object carelessly
Avoid saving a UI context in places that outlive the screen unless you truly need the application context.
5. Using old Compose APIs from outdated examples
Your original code uses older Compose syntax like Padding and FlexRow. Modern Compose usually uses Row, Modifier.padding(...), and updated Material components. Be careful when copying old examples.
Comparisons
| Approach | How it gets Context | Best use case | Notes |
|---|---|---|---|
LocalContext.current | Read from Compose composition | Inside composables | Standard Compose approach |
this@MainActivity | Reference the activity directly | Rarely inside Compose UI | Tightly coupled and often not available |
Passing Context as a parameter | Sent from caller | Special reusable APIs | Can work, but often unnecessary in Compose |
applicationContext | App-level context | Long-lived, app-wide tasks | Not always suitable for UI-specific work |
LocalContext.current vs passing Context
| Option | Pros | Cons |
|---|---|---|
LocalContext.current | Simple, idiomatic, easy inside composables | Only available in composable scope |
Pass Context parameter | Explicit dependency | More boilerplate, can clutter APIs |
Activity vs Context
| Type | What it represents | When to use |
|---|---|---|
Context | General Android environment | Most framework APIs like Toast |
Activity | A screen with lifecycle and UI hosting | Only when you specifically need activity-only features |
Cheat Sheet
val context = LocalContext.current
Toast.makeText(context, "Hello", Toast.LENGTH_SHORT).show()
Rules
- Use
LocalContext.currentinside composables - Add
@Composableto the function readingLocalContext.current - Prefer
Contextover directly referencing anActivity - Use
Contextonly for Android-specific work
Common import
import androidx.compose.ui.platform.LocalContext
Basic pattern
@Composable
fun MyButton() {
val context = LocalContext.current
Button(onClick = {
Toast.makeText(context, "Clicked", Toast.LENGTH_SHORT).show()
}) {
Text("Click")
}
}
Edge cases
LocalContext.currentonly works inside composables- Do not assume the context is always a specific activity class
- Old Compose examples may use outdated layout APIs
- If you need activity-only APIs, you may need to cast carefully or use another pattern
FAQ
How do I get Context in Jetpack Compose?
Use LocalContext.current inside a composable.
Can I use this@MainActivity inside a composable?
Usually you should not. Composables are not activity instances, and this creates tight coupling.
Why does Toast.makeText() need a context?
Toast is an Android framework API and needs the current app or UI environment to display itself.
Does LocalContext.current return an Activity?
Not necessarily. It returns a Context. Sometimes that context is backed by an activity, but you should not assume that unless required.
Can I call LocalContext.current outside a composable?
No. It must be used from a composable function.
Is it okay to show a toast directly in a composable click handler?
Yes, for simple UI feedback this is normal. For larger app logic, keep business decisions outside the composable.
What is the modern Compose way to replace old layout code like FlexRow?
Modern Compose usually uses Row, Column, and Modifier APIs instead of older layout syntax.
Should I pass context into every composable?
Usually no. Prefer LocalContext.current when the composable itself needs Android context.
Mini Project
Description
Build a small Compose screen that shows a list of items, each with a button. When the user taps a button, a toast should display the item number. This demonstrates how to access Context correctly in Jetpack Compose and use it inside event handlers.
Goal
Create a reusable composable list item that uses LocalContext.current to show a toast when its button is clicked.
Requirements
- Create a composable function for a single list item.
- Display the item number as text.
- Add a button for each item.
- Show a toast with the item number when the button is clicked.
- Use
LocalContext.currentinstead of directly referencing an activity.
Keep learning
Related questions
Accessing Kotlin Extension Functions from Java
Learn how Kotlin extension functions are compiled and how to call them correctly from Java with clear examples and common pitfalls.
Add a Maven Repository URL in Gradle Kotlin DSL (build.gradle.kts)
Learn how to add Maven Central and a custom Maven repository URL in Gradle Kotlin DSL using build.gradle.kts syntax.
Allow HTTP and HTTPS in Android 9 Pie with Network Security Configuration
Learn how Android 9 Pie handles cleartext HTTP traffic and how to allow HTTP and HTTPS safely using network security config.