# Shape Theming
Material Design encourages brand expression through shapes. The Material
Components library offers a `shape` library that can be used to create
non-standard shapes using a `MaterialShapeDrawable`, a `Drawable` that can draw
custom shapes while taking shadows, elevation, scale and color into account.
On top of the shape library, the Material Components library provides a
mechanism with which to easily customize component shapes across at the theme
level. Shape theming offers a new dimension with which to customize the look and
feel of your app.
## Design & API Documentation
- [Material Design guidelines:
Shape](https://material.io/go/design-shape)
## How it works
### `MaterialShapeDrawable` and `ShapeAppearanceModel`
`MaterialShapeDrawable` draws itself using a path generated by a
`ShapeAppearanceModel`. A `ShapeAppearanceModel` is made of `CornerTreatment`s
and `EdgeTreatment`s that combine to create a custom shape path, and is
generally passed in to a MaterialShapeDrawable's constructor.
The `shape` library provides some subclassed `CornerTreatment`s and
`EdgeTreatment`s to allow for easily building new shapes:
- [`CutCornerTreatment`](https://developer.android.com/reference/com/google/android/material/shape/CutCornerTreatment)
- [`RoundedCornerTreatment`](https://developer.android.com/reference/com/google/android/material/shape/RoundedCornerTreatment)
- [`TriangleEdgeTreatment`](https://developer.android.com/reference/com/google/android/material/shape/TriangleEdgeTreatment)
Both `CornerTreatment` and `EdgeTreatment` can be subclassed to create custom
corners and edges.
Note: When subclassing `CornerTreatment` or `EdgeTreatment`, make sure to
implement the `Cloneable` interface to ensure that the `ShapeAppearanceModel`
can create deep copies of the corner and edge treatments.
### Theming `MaterialShapeDrawable`s
Components backed by `MaterialShapeDrawable`s can be themed across an
application.
#### Shape Theme Attributes
Theme attributes are provided to be set at the theme level to change the shape
values that components read in to set their shapes.
Attribute Name | Description | Default Value
-------------------------------- | ---------------------- | -------------
`shapeAppearanceSmallComponent` | Style reference that contains shape values that are used to style small components | 4dp rounded
`shapeAppearanceMediumComponent` | Style reference that contains shape values that are used to style medium components | 4dp rounded
`shapeAppearanceLargeComponent` | Style reference that contains shape values that are used to style large components | 0dp rounded
Aside from defining these attributes in your theme, you likely will not need to
reference these attributes at all; the widget styles are already mapped to the
appropriate theme attribute to create a seamless shape theming experience. To
change individual shapes throughout your app, you should use the
[shapeAppearance and shapeAppearanceOverlay](#shapeappearance-and-shapeappearanceoverlay-attributes)
attributes rather than redefining these theme level attributes.
## Usage
### Building a Shape Appearance
Component shapes are backed by "shape appearances", which are style reference
that define aspects of the shape. `ShapeAppearanceModel` reads in the
`shapeAppearance` style and creates corner and edge treatments out of the
`shapeAppearance` values.
The following attributes can be used in a `shapeAppearance` style:
Attribute Name | Format | Description | Supported Values
------------------------- | --------- | ---------------- | ----------------
`cornerFamily` | enum | corner family to be used for all four corners | rounded, cut
`cornerFamilyTopLeft` | enum | corner family to be used for the top left corner | rounded, cut
`cornerFamilyTopRight` | enum | corner family to be used for the top right corner | rounded, cut
`cornerFamilyBottomRight` | enum | corner family to be used for the bottom right corner | rounded, cut
`cornerFamilyBottomLeft` | enum | corner family to be used for the bottom left corner | rounded, cut
`cornerSize` | dimension | corner size to be used for all four corners | `dp` values
`cornerSizeTopLeft` | dimension | corner size to be used for the top left corner | `dp` values
`cornerSizeTopRight` | dimension | corner size to be used for the top right corner | `dp` values
`cornerSizeBottomRight` | dimension | corner size to be used for the bottom right corner | `dp` values
`cornerSizeBottomLeft` | dimension | corner size to be used for the bottom left corner | `dp` values
To build a `shapeAppearance`, you need at least a **`cornerSize`** and
**`cornerFamily`** value specified for each corner.
#### `ShapeAppearance` and `shapeAppearanceOverlay` attributes
Two attributes are provided to set a component's shape style, `shapeAppearance`
and `shapeAppearanceOverlay`:
Attribute Name | Description
------------------------ | --------------------------------------
`shapeAppearance` | Style reference that contains shape values that are used to style the component. Should point to a theme attribute style reference such as `?attr/shapeAppearanceSmallComponent`.
`shapeAppearanceOverlay` | Style reference that contains shape values that layer on top of a `shapeAppearance` style. This attribute is intended for overrides on top of the themed shapeAppearance shape values, and should map to a custom style reference rather than a themed style reference.
The `shapeAppearanceOverlay` attribute is provided to override components on a
case by case basis. This attribute stacks on top of the `shapeAppearance`
attribute; the `shapeAppearance` is read in first, and then if there is anything
specified in the `shapeAppearanceOverlay` attribute, it overrides what’s set in
the `shapeAppearance`.
Note: `shapeAppearance` styles require both `cornerSize` and `cornerFamily` to
be set, while `shapeAppearanceOverlay` does not. This means that when defining
custom `shapeAppearance` style, you should either inherit from a parent if one
exists, or set both `cornerSize` and `cornerFamily`. However, when defining a
style to be used as a `shapeAppearanceOverlay`, you should generally set an
empty parent by setting `parent=""`. This is because `shapeAppearanceOverlay`
stacks on top of `shapeAppearance`, so all values will be set in the
`shapeAppearance.`
### Using `shapeAppearance` in the theme
The Material Components library supports theming shapes at the application
level. To theme shapes across your app, specify the shape theme attributes in
your theme. This will allow
[components that support shape theming](#supported-components) to read in the
customized values and change their shapes accordingly.
Let's say you want to change the small and medium components' corners in your
app to cut corners. To accomplish this, define the shape theme attributes to
point to custom style references that contain shape values:
```xml
```
The shape theme attributes should point to custom `shapeAppearance` styles that
define both `cornerSize` and `cornerFamily`. These `shapeAppearance` styles
might look something like this:
```xml
```
Material components that support shape theming read in the theme attributes and
style themselves according to the themed shape values.
### Customizing component shapes
#### Theme-wide component overrides
You can change a component's shape across the entire app by defining a custom
`shapeAppearanceOverlay` in the component's style.
Let's say you wanted to modify `MaterialCardView` so that it uses 16dp rounded
corners across the entire app. All you'd have to do is define your own card
style that extends from the widget's style, and set the relevant attributes to
the desired theme attributes:
```xml
```
And define `ShapeAppearanceOverlay.MyApp.MaterialCardView` as follows:
```xml
```
Then make sure to set component's style in your theme to your custom style:
```xml
```
All cards in your app should now have 16dp rounded corners.
#### Individual component overrides
You can also change an individual component's shape on a case by case basis.
Let's say cards in your theme have 16dp rounded corners, but there's one card
that should have 16dp cut corners. To change that card's `cornerFamily`, you can
set the `shapeAppearanceOverlay` attribute on the card in your layout.
Define a custom `shapeAppearanceOverlay` style with just the attribute you want
to overlay on top of the existing `shapeAppearance`. In this case, you would set
`cornerFamily` to `cut`:
```xml
```
Then, set the card's `shapeAppearanceOverlay` attribute to that
`ShapeAppearanceOverlay` style in your layout:
```xml
```
The `cornerFamily` attribute set in the `shapeAppearanceOverlay` will override
the `cornerFamily` set in the card's `shapeAppearance`, so the card should now
have 16dp cut corners instead of 16dp rounded corners.
#### Supported Components
The following are some Material components that support shape theming.
Components that support shape theming have a `shapeAppearance` attribute, a
`shapeAppearanceOverlay` attribute, and are backed by a `MaterialShapeDrawable`.
* [Bottom Sheet](../components/BottomSheetBehavior.md)
* [Card](../components/Card.md)
* [Chip](../components/Chip.md)
* [Date Picker](../components/DatePicker.md)
* [Dialog](../components/Dialog.md)
* [Extended Floating Action Button](../components/FloatingActionButton.md?#extended-fabs)
* [Floating Action Button](../components/FloatingActionButton.md)
* [Button](../components/Button.md)
* [Toggle Button](../components/Button.md?#toggle-button)
* [Navigation Drawer](../components/NavigationDrawer.md)
* [Slider](../components/Slider.md)
* [Text Field](../components/TextField.md)