Material Components

Material Components for Android (the com.google.android.material library) is Google's own official implementation of the Material Design system — the buttons, text fields, cards, and navigation widgets that give a modern Android app its familiar, polished feel. This lesson tours the components TrailLog leans on most, and builds its "add trail" form as a full worked example.

Commonly Used Material Components

ComponentWhat It's For
MaterialButtonA Material-styled button — filled, outlined, or text style — replacing the plain Button widget.
TextInputLayout + TextInputEditTextA text field with a floating label that animates above the input as the user types, plus built-in support for showing an error message beneath the field.
FloatingActionButtonA circular, elevated button reserved for a screen's single most important action — on TrailLog's list screen, this is the "add new trail" button.
MaterialCardViewA Material-styled card with proper elevation, corner radius, and stroke support — used for each row in TrailLog's trail list.
BottomNavigationViewA row of destinations pinned to the bottom of the screen, for switching between a small number of top-level sections (for example, Trails, Map, and Profile).

The Required Base Theme

Material Components have a real, common beginner gotcha: they need the app's theme (in res/values/themes.xml) to descend from a Material theme, or they render broken and unstyled — flat, colorless, missing the elevation and ripple effects that define Material Design.

<!-- res/values/themes.xml -->
<style name="Theme.TrailLog" parent="Theme.Material3.DayNight.NoActionBar">
    <item name="colorPrimary">@color/trail_green</item>
</style>

Theme.Material3.DayNight is Google's current Material 3 base theme, and the DayNight part means it automatically switches between a light and dark palette based on the system setting. If a MaterialButton or TextInputLayout in TrailLog ever looks plain, square, or oddly colored, the very first thing to check is whether the app's theme actually extends a Theme.Material3 (or the older Theme.MaterialComponents) parent rather than a plain Theme.AppCompat one.

Worked Example: TrailLog's Add-Trail Form

Here's the name field from TrailLog's "add trail" screen, using TextInputLayout wrapped around a TextInputEditText:

<!-- res/layout/fragment_add_trail.xml (excerpt) -->
<com.google.android.material.textfield.TextInputLayout
    android:id="@+id/nameInputLayout"
    android:hint="Trail name"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <com.google.android.material.textfield.TextInputEditText
        android:id="@+id/nameEditText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</com.google.android.material.textfield.TextInputLayout>

android:hint on the TextInputLayout (not the inner EditText) is what becomes the floating label. When the user taps in and the field is empty, "Trail name" sits inside the box as a normal hint; once they start typing, it animates up above the input, staying visible even while there's text in the field.

Validating the field and showing an error uses a single property on the TextInputLayout:

private fun validateName(): Boolean {
    val name = binding.nameEditText.text?.toString()?.trim().orEmpty()
    return if (name.isEmpty()) {
        binding.nameInputLayout.error = "Name is required"
        false
    } else {
        binding.nameInputLayout.error = null // clear any previous error
        true
    }
}

Setting textInputLayout.error draws the error text in red beneath the field and outlines the box in the error color — all built in, with no manual view for the error message needed. Setting it back to null once the field becomes valid clears that state.

Worked Example: The FloatingActionButton

TrailLog's trail list screen anchors a FloatingActionButton to its bottom-right corner as the one obvious way to log a new hike:

<com.google.android.material.floatingactionbutton.FloatingActionButton
    android:id="@+id/addTrailFab"
    android:contentDescription="Add trail"
    app:srcCompat="@drawable/ic_add"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_margin="16dp"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent" />

Wiring it up in the Fragment launches the add-trail screen:

binding.addTrailFab.setOnClickListener {
    findNavController().navigate(R.id.action_trailList_to_addTrail)
}
Note: This XML and Kotlin are correct and match how a real TrailLog project would be structured, but this website's own project doesn't run a live Android Studio build, so nothing here renders on the page itself.
Up next: Dialogs, Toast & Snackbar covers how TrailLog confirms actions and gives feedback — like letting a user undo a deleted trail.