Cards contain content and actions about a single subject.
There are two types of cards:
Before you can use a Material card, you need to add a dependency to the Material Components for Android library. For more information, go to the Getting started page.
Cards support checking and dragging, but those behaviors are not implemented by default.
The contents within a card should follow their own accessibility guidelines, such as images having content description set on them.
If you have a draggable card, you should set an
AccessibilityDelegate
on it, so that the behavior can be accessible via screen readers such as
TalkBack. More info about it under the
draggable card section.
On mobile, a card’s default elevation is 1dp, with a raised dragged elevation of 8dp.
Source code API:
MaterialCardView
Note: You don't need to specify a style tag as long as you are using a
Material Components Theme. If not, set the style to
Widget.MaterialComponents.CardView.
The following example shows an elevated card.
In the layout:
<com.google.android.material.card.MaterialCardView
android:layout_width="@dimen/card_width"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:clickable="true"
android:focusable="true"
android:minHeight="@dimen/card_min_height">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<!-- Media -->
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="match_parent"
android:layout_height="194dp"
android:background="@android:color/transparent"
android:contentDescription="@string/media_image_view_description"
app:srcCompat="@drawable/card_sample_image" />
<!-- Title and supporting text -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
style="?attr/textAppearanceHeadline6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/card_title" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/secondary_text" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/supporting_text" />
<!-- Buttons -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
style="?attr/borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:text="@string/action_1" />
<com.google.android.material.button.MaterialButton
style="?attr/borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:text="@string/action_2" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>The following example shows an outlined card.
In the layout:
<com.google.android.material.card.MaterialCardView
...
app:strokeWidth="1dp"
app:strokeColor="@color/gray"
app:cardElevation="0dp">
...
<!-- Card contents (same as elevated card example). -->
</com.google.android.material.card.MaterialCardView>When a card is checked, it will show a checked icon and change the foreground color. There is no default behavior for enabling/disabling the checked state. An example of how to do it in response to a long click is shown below.
In the layout:
<com.google.android.material.card.MaterialCardView
...
android:clickable="true"
android:focusable="true"
android:checkable="true">
...
</com.google.android.material.card.MaterialCardView>In code:
card.setOnLongClickListener {
card.setChecked(!card.isChecked)
true
}Cards have an app:state_dragged that has foreground and elevation changes to
convey motion. The recommended way of using the dragged state is via the
ViewDragHelper:
private inner class ViewDragHelperCallback : ViewDragHelper.Callback() {
override fun onViewCaptured(capturedChild: View, activePointerId: Int) {
if (capturedChild is MaterialCardView) {
(view as MaterialCardView).setDragged(true)
}
}
override fun onViewReleased(releaseChild: View, xVel: Float, yVel: Float) {
if (releaseChild is MaterialCardView) {
(view as MaterialCardView).setDragged(false)
}
}
}Alternatively, the
Material Catalog
has an implementation example that uses a custom class called
DraggableCoordinatorLayout
that you can copy, which is used as the parent container in the layout:
<io.material.catalog.draggable.DraggableCoordinatorLayout
android:id="@+id/parentContainer"
...
>
<com.google.android.material.card.MaterialCardView
...
>
<!-- Card contents. -->
</com.google.android.material.card.MaterialCardView>
</io.material.catalog.draggable.DraggableCoordinatorLayout>Then, in code:
parentContainer.addDraggableChild(card)
parentContainer.setViewDragListener(object : DraggableCoordinatorLayout.ViewDragListener {
override fun onViewCaptured(view: View, pointerId: Int) {
card.isDragged = true
}
override fun onViewReleased(view: View, vX: Float, vY: Float) {
card.isDragged = false
}
})Finally, make sure to make the behavior is accessible by setting an
AccessibilityDelegate
on the card. The following shows an example of allowing the user to move the
card to two different positions on the screen.
private val cardDelegate = object : AccessibilityDelegate() {
override fun onInitializeAccessibilityNodeInfo(host: View, info: AccessibilityNodeInfo) {
super.onInitializeAccessibilityNodeInfo(host, info)
val layoutParams = card!!.layoutParams as CoordinatorLayout.LayoutParams
val gravity = layoutParams.gravity
val isOnTop = gravity and Gravity.TOP == Gravity.TOP
val isOnBottom = gravity and Gravity.BOTTOM == Gravity.BOTTOM
if (!isOnTop) {
info.addAction(AccessibilityAction(R.id.move_card_top_action, getString(R.string.card_action_move_top)))
}
if (!isOnBottom) {
info.addAction(AccessibilityAction(R.id.move_card_bottom_action, getString(R.string.card_action_move_bottom)))
}
}
override fun performAccessibilityAction(host: View, action: Int, arguments: Bundle): Boolean {
val gravity: Int
if (action == R.id.move_card_top_action) {
gravity = Gravity.TOP
} else if (action == R.id.move_card_bottom_action) {
gravity = Gravity.BOTTOM
} else {
return super.performAccessibilityAction(host, action, arguments)
}
val layoutParams = card!!.layoutParams as CoordinatorLayout.LayoutParams
if (layoutParams.gravity != gravity) {
layoutParams.gravity = gravity
card!!.requestLayout()
}
return true
}
}Note: Cards also support a swipe-to-dismiss behavior through the use of 'SwipeDismissBehavior'. An example can be found on the catalog.
- Container
- Thumbnail (optional)
- Header text (optional)
- Subhead (optional)
- Media (optional)
- Supporting text (optional)
- Buttons (optional)
- Icons (optional)
Note: All the optional elements of a card's content are implemented through the use of other views/components, as shown on the card example section. With the exception of the optional checked icon, explained below.
| Attribute | Related method(s) | Default value | |
|---|---|---|---|
| Margin (left) | android:layout_marginLeft |
N/A | N/A (recommended: 8dp) |
| Margin (right) | android:layout_marginRight |
N/A | N/A (recommended: 8dp) |
| Margin (top) | android:layout_marginTop |
N/A | N/A (recommended: 8dp) |
| Elevation | app:cardElevation |
setCardElevationsetCardMaxElevation |
1dp |
| Stroke color | app:strokeColor |
setStrokeColorgetStrokeColorgetStrokeColorStateList |
@null |
| Stroke width | app:strokeWidth |
setStrokeWidthgetStrokeWidth |
0dp |
| Background color | app:cardBackgroundColor |
setCardBackgroundColorgetCardBackgroundColor |
?attr/colorSurface |
| Foreground color | app:cardForegroundColor |
setCardForegroundColorgetCardForegroundColor |
@android:color/transparent (see all states) |
| Ripple color | app:rippleColor |
setRippleColorsetRippleColorResourcegetRippleColor |
?attr/colorOnSurface at 20% opacity (see all states) |
| Shape | app:shapeAppearance |
setShapeAppearanceModelgetShapeAppearanceModel |
?attr/shapeAppearanceMediumComponent |
Note about the margins
It's recommended that cards on mobile have 8dp margins.
android:layout_margin needs to be set directly on a View in its layout and
won't work when included as part of a style.
Note about the stroke
Without an app:strokeColor, the card will not render a stroked border,
regardless of the app:strokeWidth value.
| Attribute | Related method(s) | Default value | |
|---|---|---|---|
| Icon | checkedIcon |
setCheckedIconsetCheckedIconResourcegetCheckedIcon |
@drawable/ic_mtrl_checked_circle.xml |
| Tint | checkedIconTint |
setCheckedIconTintgetCheckedIconTint |
?attr/colorPrimary |
| To make card checkable | android:checkable |
setCheckableisCheckable |
false |
Cards have the following states:
| State | Description | Related method(s) |
|---|---|---|
| Default | Card is not checked and not dragged | N/A |
Checked (android:state_checked) |
true if a card is checked |
setCheckedsetOnCheckedChangeListenerisChecked |
Dragged (app:state_dragged) |
true when a card is being dragged |
setDraggedisDragged |
| Style | |
|---|---|
| Default style | Widget.MaterialComponents.CardView |
Default style theme attribute: ?attr/materialCardViewStyle
See the full list of styles and attrs.
A card supports Material Theming and can be customized in terms of color, typography and shape.
API and source code
MaterialCardView
Using theme attributes and styles in res/values/styles.xml (themes all cards
and affects other components):
<style name="Theme.App" parent="Theme.MaterialComponents.*">
...
<item name="colorPrimary">@color/shrine_pink_100</item>
<item name="colorOnPrimary">@color/shrine_pink_900</item>
<item name="colorOnSurface">@color/shrine_pink_900</item>
<item name="shapeAppearanceMediumComponent">@style/ShapeAppearance.App.MediumComponent</item>
</style>
<style name="ShapeAppearance.App.MediumComponent" parent="ShapeAppearance.MaterialComponents.MediumComponent">
<item name="cornerFamily">cut</item>
<item name="cornerSize">8dp</item>
</style>
<!-- You still need the individual card styles to change non-theme attributes, like strokeWidth, strokeColor, etc.
See the example below. -->or using default style theme attributes, styles and theme overlays (themes all buttons but does not affect other components):
<style name="Theme.App" parent="Theme.MaterialComponents.*">
...
<item name="materialCardViewStyle">@style/Widget.MaterialComponents.CardView</item>
</style>
<style name="Widget.App.Card" parent="Widget.MaterialComponents.CardView">
<item name="materialThemeOverlay">@style/ThemeOverlay.App.Card</item>
<item name="shapeAppearance">@style/ShapeAppearance.App.MediumComponent</item>
</style>
<style name="ThemeOverlay.App.Card" parent="">
<item name="colorPrimary">@color/shrine_pink_100</item>
<item name="colorOnPrimary">@color/shrine_pink_900</item>
<item name="colorOnSurface">@color/shrine_pink_900</item>
</style>or using one of the styles in the layout (affects only this specific card):
<com.google.android.material.card.MaterialCardView
...
style="@style/Widget.App.Card"
/>




