Question

How to Get Context in Jetpack Compose for Toast Messages in Kotlin

kotlinandroidandroid-jetpackandroid-jetpack-compose

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.

Take Quiz

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.current gives the current Android Context
  • The context value can be used inside the button's onClick
  • 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:

  1. Compose starts building the UI for ToastButton.
  2. val context = LocalContext.current asks Compose for the current Android Context.
  3. Compose stores that context value for this composition.
  4. The Button is displayed on screen.
  5. The user taps the button.
  6. The onClick lambda runs.
  7. Toast.makeText(context, "Clicked item $itemIndex", Toast.LENGTH_SHORT) creates a toast.
  8. .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
  • Working with files or preferences

    • Accessing app storage helpers that need a Context

Example scenario

In a shopping app:

  • User taps Add to cart
  • A toast says Item added to cart
  • The composable uses LocalContext.current to create that toast

In a form screen:

  • User presses Submit
  • Validation fails
  • A toast or Android service might need a Context
Take Quiz

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.current for 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
  • this may 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.current can 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 context only 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

ApproachHow it gets ContextBest use caseNotes
LocalContext.currentRead from Compose compositionInside composablesStandard Compose approach
this@MainActivityReference the activity directlyRarely inside Compose UITightly coupled and often not available
Passing Context as a parameterSent from callerSpecial reusable APIsCan work, but often unnecessary in Compose
applicationContextApp-level contextLong-lived, app-wide tasksNot always suitable for UI-specific work

LocalContext.current vs passing Context

OptionProsCons
LocalContext.currentSimple, idiomatic, easy inside composablesOnly available in composable scope
Pass Context parameterExplicit dependencyMore boilerplate, can clutter APIs

Activity vs Context

TypeWhat it representsWhen to use
ContextGeneral Android environmentMost framework APIs like Toast
ActivityA screen with lifecycle and UI hostingOnly when you specifically need activity-only features
Take Quiz

Cheat Sheet

val context = LocalContext.current
Toast.makeText(context, "Hello", Toast.LENGTH_SHORT).show()

Rules

  • Use LocalContext.current inside composables
  • Add @Composable to the function reading LocalContext.current
  • Prefer Context over directly referencing an Activity
  • Use Context only 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.current only 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.

Take Quiz

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.current instead of directly referencing an activity.
Take Quiz

Keep learning

Related questions

View more