Merge branch 'release-candidate' into stable
diff --git a/.kokoro b/.kokoro
index ace28b8..9c40fac 100755
--- a/.kokoro
+++ b/.kokoro
@@ -17,34 +17,24 @@
 # Fail on any error.
 set -e
 
-KOKORO_RUNNER_VERSION="v4.*"
-
 XCODE_MINIMUM_VERSION="9.0.0"
 
 fix_bazel_imports() {
-  if [ -z "$KOKORO_BUILD_NUMBER" ]; then
-    tests_dir_prefix=""
-  else
-    tests_dir_prefix="github/repo/"
-  fi
-  
+  echo "Rewriting imports for bazel..."
+
   private_components() {
-    if [ -z "$KOKORO_BUILD_NUMBER" ]; then
-      find "components/private" -type d | cut -d'/' -f3 | sort | uniq
-    else
-      find "github/repo/components/private" -type d | cut -d'/' -f5 | sort | uniq
-    fi
+    find "components/private" -type d | cut -d'/' -f3 | sort | uniq
   }
   
   rewrite_tests() {
-    find "${stashed_dir}${tests_dir_prefix}"components/private/*/tests/unit -type f -name '*.swift' -exec perl -pi -e "$1" {} + || true
-    find "${stashed_dir}${tests_dir_prefix}"components/*/tests/unit -type f -name '*.swift' -exec perl -pi -e "$1" {} + || true
+    find "${stashed_dir}"components/private/*/tests/unit -type f -name '*.swift' -exec perl -pi -e "$1" {} + || true
+    find "${stashed_dir}"components/*/tests/unit -type f -name '*.swift' -exec perl -pi -e "$1" {} + || true
   }
   rewrite_source() {
-    find "${stashed_dir}${tests_dir_prefix}"components/private/*/src -type f -name '*.h' -exec perl -pi -e "$1" {} + || true
-    find "${stashed_dir}${tests_dir_prefix}"components/private/*/src -type f -name '*.m' -exec perl -pi -e "$1" {} + || true
-    find "${stashed_dir}${tests_dir_prefix}"components/*/src -type f -name '*.h' -exec perl -pi -e "$1" {} + || true
-    find "${stashed_dir}${tests_dir_prefix}"components/*/src -type f -name '*.m' -exec perl -pi -e "$1" {} + || true
+    find "${stashed_dir}"components/private/*/src -type f -name '*.h' -exec perl -pi -e "$1" {} + || true
+    find "${stashed_dir}"components/private/*/src -type f -name '*.m' -exec perl -pi -e "$1" {} + || true
+    find "${stashed_dir}"components/*/src -type f -name '*.h' -exec perl -pi -e "$1" {} + || true
+    find "${stashed_dir}"components/*/src -type f -name '*.m' -exec perl -pi -e "$1" {} + || true
   }
 
   stashed_dir=""
@@ -56,6 +46,7 @@
     fi
     rewrite_tests "s/import MaterialComponents.Material$private_component/import components_private_${private_component}_${private_component}/"
   done
+  rewrite_tests "s/import MaterialComponentsAlpha.Material(.+)_(.+)/import components_\1_\2 \/\/ Alpha/"
   rewrite_tests "s/import MaterialComponentsAlpha.Material(.+)/import components_\1_\1 \/\/ Alpha/"
   rewrite_tests "s/import MaterialComponents.Material(.+)/import components_\1_\1/"
   rewrite_source "s/import <Motion(.+)\/Motion.+\.h>/import \"Motion\1.h\"/"
@@ -64,6 +55,8 @@
   rewrite_tests "s/import MDFInternationalization/import material_internationalization_ios_MDFInternationalization/"
   stashed_dir="$(pwd)/"
   reset_imports() {
+    echo "Undoing import rewrites for bazel..."
+
     # Undoes our source changes from above.
     rewrite_tests "s/import components_(.+)_\1 \/\/ Alpha/import MaterialComponentsAlpha.Material\1/"
     rewrite_tests "s/import components_schemes_(.+)_.+/import MaterialComponents.Material\1Scheme/"
@@ -128,6 +121,33 @@
   done
 }
 
+# Uploads all of the bazel test artifacts to Kokoro's artifacts storage.
+upload_bazel_test_artifacts() {
+  logs_dir="$KOKORO_ARTIFACTS_DIR/bazel_test_logs"
+  mkdir -p "$logs_dir"
+
+  # Copies each file from stdin to $KOKORO_ARTIFACTS_DIR and preserves the directory structure
+  copy_to_artifacts() {
+    cat - | while read file; do
+      directory="$logs_dir/$(dirname $file)"
+      mkdir -p "$directory"
+      cp "$file" "$logs_dir/$file"
+    done
+  }
+
+  brew install rename
+
+  # rename all test.log to sponge_log.log and then copy them to the kokoro
+  # artifacts directory.
+  find -L . -name "test.log" -type f -exec rename 's/test.log/sponge_log.log/' {} \;
+  find -L . -name "sponge_log.log" -type f | copy_to_artifacts
+
+  # rename all test.xml to sponge_log.xml and then copy them to kokoro
+  # artifacts directory.
+  find -L . -name "test.xml" -type f -exec rename 's/test.xml/sponge_log.xml/' {} \;
+  find -L . -name "sponge_log.xml" -type f | copy_to_artifacts
+}
+
 run_bazel() {
   echo "Running bazel builds..."
 
@@ -135,14 +155,12 @@
     move_derived_data_to_tmp
   fi
 
-  fix_bazel_imports
-
   if [ -n "$KOKORO_BUILD_NUMBER" ]; then
     bazel version
   fi
 
   if [ -n "$VERBOSE_OUTPUT" ]; then
-    verbosity_args="-v"
+    verbosity_args="-s"
   fi
 
   if [ -z "$COMMAND" ]; then
@@ -152,17 +170,51 @@
     TARGET="//components/..."
   fi
 
-  if [ -n "$XCODE_VERSION" ]; then
-    xcode_versions="--xcode-version $XCODE_VERSION"
-  else
-    xcode_versions="--min-xcode-version $XCODE_MINIMUM_VERSION"
+  if [ -n "$KOKORO_BUILD_NUMBER" ]; then
+    select_xcode "$XCODE_VERSION"
+
+    # Move into our cloned repo
+    cd github/repo
   fi
 
-  ./.kokoro-ios-runner/bazel.sh $COMMAND $TARGET \
-      $xcode_versions \
-      $verbosity_args \
-      --ios_minimum_os=8.0 \
-      --ios_multi_cpus=i386,x86_64
+  # Run against whichever Xcode is currently selected.
+  selected_xcode_developer_path=$(xcode-select -p)
+  selected_xcode_contents_path=$(dirname "$selected_xcode_developer_path")
+
+  xcode_version=$(cat "$selected_xcode_contents_path/version.plist" \
+    | grep "CFBundleShortVersionString" -A1 \
+    | grep string \
+    | cut -d'>' -f2 \
+    | cut -d'<' -f1)
+  if [ -n "$MIN_XCODE_VERSION" ]; then
+    xcode_version_as_number="$(version_as_number $xcode_version)"
+
+    if [ "$xcode_version_as_number" -lt "$MIN_XCODE_VERSION" ]; then
+      echo "The currently selected Xcode version ($xcode_version_as_number) is less than the desired version ($MIN_XCODE_VERSION)."
+      echo "Stopping execution..."
+      exit 1
+    fi
+  fi
+
+  if [ "$COMMAND" == "build" ]; then
+    echo "🏗️  $COMMAND with Xcode $xcode_version..."
+  elif [ "$COMMAND" == "test" ]; then
+    echo "🛠️  $COMMAND with Xcode $xcode_version..."
+
+    if [ -n "$VERBOSE_OUTPUT" ]; then
+      extra_args="--test_output=all"
+    else
+      extra_args="--test_output=errors"
+    fi
+  fi
+
+  fix_bazel_imports
+  if [ -n "$KOKORO_ARTIFACTS_DIR" ]; then
+    # Especially in the event of failure, we want our test artifacts to be uploaded.
+    trap upload_bazel_test_artifacts EXIT
+  fi
+  bazel clean
+  bazel $COMMAND $TARGET --xcode_version $xcode_version --ios_minimum_os=8.0 --ios_multi_cpus=i386,x86_64 $extra_args $verbosity_args
 }
 
 run_cocoapods() {
@@ -224,14 +276,16 @@
       if [ -n "$IS_RELEASE" ]; then
         bash scripts/test_all
       else
-        bash scripts/test_all catalog/MDCCatalog.xcworkspace:MDCUnitTests
+        bash scripts/test_all catalog/MDCCatalog.xcworkspace:MDCCatalog
       fi
     elif [ "$DEPENDENCY_SYSTEM" = "cocoapods-podspec" ]; then
-      pod lib lint MaterialComponents.podspec
+      pod lib lint MaterialComponents.podspec --verbose --skip-tests
     fi
   done
 
-  bash <(curl -s https://codecov.io/bash)
+  if [ -n "$CODECOV_TOKEN" ]; then
+    bash <(curl -s https://codecov.io/bash)
+  fi
 }
 
 # For local runs, you must set the following environment variables:
@@ -572,16 +626,6 @@
   set -x
 fi
 
-if [ ! -d .kokoro-ios-runner ]; then
-  git clone https://github.com/material-foundation/kokoro-ios-runner.git .kokoro-ios-runner
-fi
-
-pushd .kokoro-ios-runner
-git fetch > /dev/null
-TAG=$(git tag --sort=v:refname -l "$KOKORO_RUNNER_VERSION" | tail -n1)
-git checkout "$TAG" > /dev/null
-popd
-
 case "$DEPENDENCY_SYSTEM" in
   "bazel")      run_bazel ;;
   "clang-format")  lint_clang_format ;;
diff --git a/.travis.yml b/.travis.yml
index fa819ec..fed091b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -51,7 +51,7 @@
   - pod repo update
   - scripts/prep_all
   - travis_wait scripts/build_all --verbose
-  - travis_wait travis_retry scripts/test_all catalog/MDCCatalog.xcworkspace:MDCUnitTests
+  - travis_wait travis_retry scripts/test_all catalog/MDCCatalog.xcworkspace:MDCCatalog
 
 # Upload our testing coverage to codecov.io.
 after_success:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cc107c8..6fb9424 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,157 @@
+# 65.0.0
+
+Bottom App Bar got a `floatingButtonVerticalOffset` property.
+ActionSheets continued work. (still in alpha).
+AlertController in dialogs: Incremental improvements to bring it up to the design guidelines and so that a themer can style it.
+Snackbar API for accessibility. 
+MDCAppBarTextColorAccessibilityMutator a deprecated class got deleted.
+
+## Breaking changes
+
+MDCAppBarTextColorAccessibilityMutator a deprecated class got deleted.
+
+## New features
+
+### ActionSheet
+
+Action sheet got the color and typography themers.
+```swift
+let actionSheet = MDCActionSheetController()
+MDCActionSheetColorThemer.applySemanticColorScheme(colorScheme, to: actionSheet)
+```
+```swift
+MDCActionSheetTypographyThemer.applyTypographyScheme(typographyScheme, to: actionSheet)
+```
+
+### BottomAppBar
+
+Bottom App Bar got a new property to offset the floating button.
+```objc
+bottomAppBar.floatingButtonVerticalOffset = 5.0f;
+```
+
+### AlertController
+
+AlertController got a themer
+
+```objc
+ MDCAlertScheme *alertScheme = [[MDCAlertScheme alloc] init];
+alertScheme.colorScheme = self.colorScheme;
+alertScheme.typographyScheme = self.typographyScheme;
+[MDCAlertControllerThemer applyScheme:alertScheme toAlertController:alertController];
+```
+
+### Snackbar
+
+To make Snackbars with action require a user action set the this property to YES.
+```
+manager.shouldEnableAccessibilityViewIsModal = YES;
+```
+
+## API changes
+
+### ActionSheet+ColorThemer
+
+**New extension.**
+
+### ActionSheet
+
+#### MDCActionSheetController
+
+*new* property: `messageTextColor` in `MDCActionSheetController`
+
+*new* property: `titleTextColor` in `MDCActionSheetController`
+
+*new* property: `inkColor` in `MDCActionSheetController`
+
+*new* property: `actionTintColor` in `MDCActionSheetController`
+
+*new* property: `imageRenderingMode` in `MDCActionSheetController`
+
+*new* property: `actionTextColor` in `MDCActionSheetController`
+
+### BottomAppBar
+
+#### MDCBottomAppBarView
+
+*new* property: `floatingButtonVerticalOffset` in `MDCBottomAppBarView`
+
+### Dialogs
+
+#### MDCAlertController
+
+*new* property: `titleAlignment` in `MDCAlertController`
+
+#### MDCAlertControllerView
+
+*new* property: `titleAlignment` in `MDCAlertControllerView`
+
+### Snackbar
+
+#### MDCSnackbarManager
+
+*new* property: `shouldEnableAccessibilityViewIsModal` in `MDCSnackbarManager`
+
+## Component changes
+
+### ActionSheet
+
+* [Add color properties to header labels (#5168)](https://github.com/material-components/material-components-ios/commit/6e91d5889980d6ab58eec7c9b7e7ab17858afe4b) (Cody Weaver)
+* [Add color themer (#5207)](https://github.com/material-components/material-components-ios/commit/b52096c7e85c88df89a26117360f1099ed4900b5) (Cody Weaver)
+* [Add test for setting fonts (#5225)](https://github.com/material-components/material-components-ios/commit/da96510c4cdad7c587bacbee02417b76799ea368) (Cody Weaver)
+* [Add test for typography theme (#5226)](https://github.com/material-components/material-components-ios/commit/f2c65f6e5270912340ec3ba887102c58733dc271) (Cody Weaver)
+* [Expose ink touch (#5201)](https://github.com/material-components/material-components-ios/commit/ff598f5da3262381e7a844cc75e4b3c922619f1b) (Cody Weaver)
+* [Expose properties for the table (#5195)](https://github.com/material-components/material-components-ios/commit/a5a4e0928ef3c4cde904bbe55634abf6fbdbf007) (Cody Weaver)
+* [Fix path for ObjC test source. (#5227)](https://github.com/material-components/material-components-ios/commit/274d492718ecd842ef003154ea685ac77aea9053) (featherless)
+* [Initial commit (#5232)](https://github.com/material-components/material-components-ios/commit/06e9b7f902fbfa8507737c791724c5f89549970b) (Cody Weaver)
+* [Open to the correct height (#5184)](https://github.com/material-components/material-components-ios/commit/886f2661a71a714a695073d94867f597874afd65) (Cody Weaver)
+* [Refactor test (#5186)](https://github.com/material-components/material-components-ios/commit/6e5f3abab68b68511cef3b56c53dc0c1bc9b6bf2) (Cody Weaver)
+* [Update cells to be testable (#5190)](https://github.com/material-components/material-components-ios/commit/75cc150e3cd5f941460fd7538d5871eae040ca3f) (Cody Weaver)
+* [Update docs to include themers (#5209)](https://github.com/material-components/material-components-ios/commit/255f6e99b4c2c371a275ab5e221a29385186d8e5) (Cody Weaver)
+* [Use correct style (#5196)](https://github.com/material-components/material-components-ios/commit/8cdd4a6330ead570e56a0c86708f0f7e2842fa31) (Cody Weaver)
+
+### AppBar
+
+* [Add an example demonstrating manual tab management. (#5161)](https://github.com/material-components/material-components-ios/commit/3ea86babf14323eef6e886252eb4e2ce51314635) (featherless)
+* [Add frame setting recommendation to app bar view controller migration guide. (#5180)](https://github.com/material-components/material-components-ios/commit/eebbe49e2f5ea02db09979fe89b3028f719dd751) (featherless)
+* [Delete the deprecated MDCAppBarTextColorAccessibilityMutator API. (#5220)](https://github.com/material-components/material-components-ios/commit/e4ff45c76eaa217a43ac733d80802421ecba9070) (featherless)
+
+### BottomAppBar
+
+* [clean up how bottom app bar path renders to avoid using hardcoded values (#5155)](https://github.com/material-components/material-components-ios/commit/c7c7b49a2e26257a9fb879fb2baba3f6ff092ccf) (Wenyu Zhang)
+* [enable customizing the vertical position of FAB   (#5138)](https://github.com/material-components/material-components-ios/commit/766a6a7697c755e6cbd012da8339e5536bd1b6ae) (Wenyu Zhang)
+
+### Dialogs
+
+* [Add/update examples for dialog themer (#5158)](https://github.com/material-components/material-components-ios/commit/5b34c0eb3a923560d81859f97f799f456a3bf554) (Galia Kaufman)
+* [Customize alert title alignment (#5164)](https://github.com/material-components/material-components-ios/commit/80145df58ed24b8e10c62f64481d722b28e3c3fc) (Galia Kaufman)
+
+### FlexibleHeader
+
+* [Extract height matching to a separate function. (#5162)](https://github.com/material-components/material-components-ios/commit/0a9206b5fd4121d6661a4e2f57cd5757199380ff) (featherless)
+* [Improve tracking scroll view switching logic. (#5178)](https://github.com/material-components/material-components-ios/commit/54853b4e1dcfabcd85bae450c2dc33d2be89089b) (featherless)
+* [[CocoaPods] Remove our tests podspec in favor of official test_spec targets. (#5204)](https://github.com/material-components/material-components-ios/commit/d238c86d47eb072617d285106147ace613321aee) (featherless)
+
+### NavigationDrawer
+
+* [Fix bug where BottomDrawer layout breaks when there isn't enough cont… (#5179)](https://github.com/material-components/material-components-ios/commit/fbaa6b5fcbb10d021f16ade8745e4322b8b43f3f) (Andrew Overton)
+
+### ShadowLayer
+
+* [Add support for responding to cornerRadius changes. (#5224)](https://github.com/material-components/material-components-ios/commit/b3e2a1e283febfd90b6f5d575c18b7bf7d51408e) (featherless)
+* [Fix layout of shadow layer example. (#5222)](https://github.com/material-components/material-components-ios/commit/d70676231566f1fe5cc8f209ca9f2027ae236d88) (featherless)
+* [Revert "Add support for responding to cornerRadius changes. (#5224)" (#5231)](https://github.com/material-components/material-components-ios/commit/cee6ae6a0f4e362c26e20ccf4d1ad9549001fec8) (featherless)
+
+### Snackbar
+
+* [Added API to make snackbar messages keep focus until an action is taken. (#5219)](https://github.com/material-components/material-components-ios/commit/669bfa82f04dbdc462eab5e56a0c6845bd5224ab) (Randall Li)
+
+### TextFields
+
+* [Remove extension check (#5182)](https://github.com/material-components/material-components-ios/commit/ebd792126341918415b0e193fe0780b61a4eb06b) (Cody Weaver)
+
+---
+
 # 64.0.0
 
 In this release
diff --git a/MaterialComponents.podspec b/MaterialComponents.podspec
index 819d3a9..7400b51 100644
--- a/MaterialComponents.podspec
+++ b/MaterialComponents.podspec
@@ -2,7 +2,7 @@
 
 Pod::Spec.new do |mdc|
   mdc.name         = "MaterialComponents"
-  mdc.version      = "64.0.0"
+  mdc.version      = "65.0.0"
   mdc.authors      = "The Material Components authors."
   mdc.summary      = "A collection of stand-alone production-ready UI libraries focused on design details."
   mdc.homepage     = "https://github.com/material-components/material-components-ios"
@@ -34,6 +34,12 @@
   #    # Only if you have a resource bundle
   #    component.resources = ["components/#{component.base_name}/src/Material#{component.base_name}.bundle"]
   #
+  #   component.test_spec 'tests' do |tests|
+  #     tests.test_spec 'unit' do |unit_tests|
+  #       unit_tests.source_files = "components/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+  #       unit_tests.resources = "components/#{component.base_name}/tests/unit/resources/*"
+  #     end
+  #   end
   #  end
   #
 
@@ -49,6 +55,13 @@
     component.dependency "MaterialComponents/Palettes"
     component.dependency "MaterialComponents/private/Application"
     component.dependency "MotionAnimator", "~> 2.0"
+
+    component.test_spec 'tests' do |tests|
+      tests.test_spec 'unit' do |unit_tests|
+        unit_tests.source_files = "components/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+        unit_tests.resources = "components/#{component.base_name}/tests/unit/resources/*"
+      end
+    end
   end
 
   mdc.subspec "ActivityIndicator+ColorThemer" do |extension|
@@ -66,6 +79,13 @@
     component.ios.deployment_target = '8.0'
     component.public_header_files = "components/#{component.base_name}/src/*.h"
     component.source_files = "components/#{component.base_name}/src/*.{h,m}", "components/#{component.base_name}/src/private/*.{h,m}"
+
+    component.test_spec 'tests' do |tests|
+      tests.test_spec 'unit' do |unit_tests|
+        unit_tests.source_files = "components/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+        unit_tests.resources = "components/#{component.base_name}/tests/unit/resources/*"
+      end
+    end
   end
 
   # AppBar
@@ -89,6 +109,13 @@
     component.dependency "MDFInternationalization"
     component.dependency "MaterialComponents/private/Icons/ic_arrow_back"
     component.dependency "MaterialComponents/private/UIMetrics"
+
+    component.test_spec 'tests' do |tests|
+      tests.test_spec 'unit' do |unit_tests|
+        unit_tests.source_files = "components/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+        unit_tests.resources = "components/#{component.base_name}/tests/unit/resources/*"
+      end
+    end
   end
 
   mdc.subspec "AppBar+ColorThemer" do |extension|
@@ -120,6 +147,13 @@
     component.dependency "MaterialComponents/Buttons"
     component.dependency "MaterialComponents/NavigationBar"
     component.dependency "MaterialComponents/private/Math"
+
+    component.test_spec 'tests' do |tests|
+      tests.test_spec 'unit' do |unit_tests|
+        unit_tests.source_files = "components/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+        unit_tests.resources = "components/#{component.base_name}/tests/unit/resources/*"
+      end
+    end
   end
 
   mdc.subspec "BottomAppBar+ColorThemer" do |extension|
@@ -144,6 +178,13 @@
     component.dependency "MaterialComponents/ShadowLayer"
     component.dependency "MaterialComponents/Typography"
     component.dependency "MaterialComponents/private/Math"
+
+    component.test_spec 'tests' do |tests|
+      tests.test_spec 'unit' do |unit_tests|
+        unit_tests.source_files = "components/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+        unit_tests.resources = "components/#{component.base_name}/tests/unit/resources/*"
+      end
+    end
   end
 
   mdc.subspec "BottomNavigation+ColorThemer" do |extension|
@@ -173,6 +214,13 @@
     component.dependency "MaterialComponents/private/Math"
     component.dependency "MaterialComponents/private/ShapeLibrary"
     component.dependency "MaterialComponents/private/Shapes"
+
+    component.test_spec 'tests' do |tests|
+      tests.test_spec 'unit' do |unit_tests|
+        unit_tests.source_files = "components/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+        unit_tests.resources = "components/#{component.base_name}/tests/unit/resources/*"
+      end
+    end
   end
 
   mdc.subspec "BottomSheet+ShapeThemer" do |extension|
@@ -198,6 +246,13 @@
     component.dependency "MaterialComponents/Typography"
     component.dependency "MaterialComponents/private/Math"
     component.dependency "MaterialComponents/private/Shapes"
+
+    component.test_spec 'tests' do |tests|
+      tests.test_spec 'unit' do |unit_tests|
+        unit_tests.source_files = "components/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+        unit_tests.resources = "components/#{component.base_name}/tests/unit/resources/*"
+      end
+    end
   end
 
   mdc.subspec "Buttons+ColorThemer" do |extension|
@@ -255,6 +310,13 @@
     component.dependency "MDFInternationalization"
     component.dependency "MaterialComponents/Buttons"
     component.dependency "MaterialComponents/private/Application"
+
+    component.test_spec 'tests' do |tests|
+      tests.test_spec 'unit' do |unit_tests|
+        unit_tests.source_files = "components/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+        unit_tests.resources = "components/#{component.base_name}/tests/unit/resources/*"
+      end
+    end
   end
 
   mdc.subspec "ButtonBar+ColorThemer" do |extension|
@@ -286,6 +348,13 @@
     component.dependency "MaterialComponents/private/Icons/ic_check_circle"
     component.dependency "MaterialComponents/private/Math"
     component.dependency "MaterialComponents/private/Shapes"
+
+    component.test_spec 'tests' do |tests|
+      tests.test_spec 'unit' do |unit_tests|
+        unit_tests.source_files = "components/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+        unit_tests.resources = "components/#{component.base_name}/tests/unit/resources/*"
+      end
+    end
   end
 
   mdc.subspec "Cards+ColorThemer" do |extension|
@@ -330,6 +399,13 @@
     component.dependency "MaterialComponents/private/Math"
     component.dependency "MaterialComponents/private/ShapeLibrary"
     component.dependency "MaterialComponents/private/Shapes"
+
+    component.test_spec 'tests' do |tests|
+      tests.test_spec 'unit' do |unit_tests|
+        unit_tests.source_files = "components/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+        unit_tests.resources = "components/#{component.base_name}/tests/unit/resources/*"
+      end
+    end
   end
 
   mdc.subspec "Chips+ChipThemer" do |extension|
@@ -400,6 +476,13 @@
     component.dependency "MaterialComponents/private/Icons/ic_radio_button_unchecked"
     component.dependency "MaterialComponents/private/Icons/ic_reorder"
     component.dependency "MaterialComponents/private/Math"
+
+    component.test_spec 'tests' do |tests|
+      tests.test_spec 'unit' do |unit_tests|
+        unit_tests.source_files = "components/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+        unit_tests.resources = "components/#{component.base_name}/tests/unit/resources/*"
+      end
+    end
   end
 
   # CollectionLayoutAttributes
@@ -408,6 +491,13 @@
     component.ios.deployment_target = '8.0'
     component.public_header_files = "components/#{component.base_name}/src/*.h"
     component.source_files = "components/#{component.base_name}/src/*.{h,m}"
+
+    component.test_spec 'tests' do |tests|
+      tests.test_spec 'unit' do |unit_tests|
+        unit_tests.source_files = "components/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+        unit_tests.resources = "components/#{component.base_name}/tests/unit/resources/*"
+      end
+    end
   end
 
   # Collections
@@ -426,6 +516,13 @@
     component.dependency "MaterialComponents/ShadowElevations"
     component.dependency "MaterialComponents/ShadowLayer"
     component.dependency "MaterialComponents/Typography"
+
+    component.test_spec 'tests' do |tests|
+      tests.test_spec 'unit' do |unit_tests|
+        unit_tests.source_files = "components/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+        unit_tests.resources = "components/#{component.base_name}/tests/unit/resources/*"
+      end
+    end
   end
 
   # Dialogs
@@ -442,6 +539,13 @@
     component.dependency "MaterialComponents/Typography"
     component.dependency "MaterialComponents/private/KeyboardWatcher"
     component.dependency "MDFInternationalization"
+
+    component.test_spec 'tests' do |tests|
+      tests.test_spec 'unit' do |unit_tests|
+        unit_tests.source_files = "components/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+        unit_tests.resources = "components/#{component.base_name}/tests/unit/resources/*"
+      end
+    end
   end
 
   mdc.subspec "Dialogs+ColorThemer" do |extension|
@@ -483,6 +587,13 @@
     component.dependency "MaterialComponents/private/Math"
     component.dependency "MaterialComponents/Typography"
     component.dependency "MDFTextAccessibility"
+
+    component.test_spec 'tests' do |tests|
+      tests.test_spec 'unit' do |unit_tests|
+        unit_tests.source_files = "components/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+        unit_tests.resources = "components/#{component.base_name}/tests/unit/resources/*"
+      end
+    end
   end
 
   mdc.subspec "FeatureHighlight+ColorThemer" do |extension|
@@ -531,6 +642,13 @@
     component.dependency 'MDFTextAccessibility'
     component.dependency "MaterialComponents/private/Application"
     component.dependency "MaterialComponents/private/UIMetrics"
+
+    component.test_spec 'tests' do |tests|
+      tests.test_spec 'unit' do |unit_tests|
+        unit_tests.source_files = "components/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+        unit_tests.resources = "components/#{component.base_name}/tests/unit/resources/*"
+      end
+    end
   end
 
   mdc.subspec "FlexibleHeader+CanAlwaysExpandToMaximumHeight" do |extension|
@@ -556,6 +674,13 @@
     component.ios.deployment_target = '8.0'
     component.public_header_files = "components/#{component.base_name}/src/*.h"
     component.source_files = "components/#{component.base_name}/src/*.{h,m}"
+
+    component.test_spec 'tests' do |tests|
+      tests.test_spec 'unit' do |unit_tests|
+        unit_tests.source_files = "components/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+        unit_tests.resources = "components/#{component.base_name}/tests/unit/resources/*"
+      end
+    end
   end
 
   mdc.subspec "HeaderStackView+ColorThemer" do |extension|
@@ -575,6 +700,13 @@
     component.source_files = "components/#{component.base_name}/src/*.{h,m}", "components/#{component.base_name}/src/private/*.{h,m}"
 
     component.dependency "MaterialComponents/private/Math"
+
+    component.test_spec 'tests' do |tests|
+      tests.test_spec 'unit' do |unit_tests|
+        unit_tests.source_files = "components/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+        unit_tests.resources = "components/#{component.base_name}/tests/unit/resources/*"
+      end
+    end
   end
 
   mdc.subspec "Ink+ColorThemer" do |extension|
@@ -592,6 +724,13 @@
     component.ios.deployment_target = '8.0'
     component.public_header_files = "components/#{component.base_name}/src/*.h"
     component.source_files = "components/#{component.base_name}/src/*.{h,m}", "components/#{component.base_name}/src/private/*.{h,m}"
+
+    component.test_spec 'tests' do |tests|
+      tests.test_spec 'unit' do |unit_tests|
+        unit_tests.source_files = "components/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+        unit_tests.resources = "components/#{component.base_name}/tests/unit/resources/*"
+      end
+    end
   end
 
   # List
@@ -607,6 +746,13 @@
     component.dependency "MaterialComponents/Typography"
     component.dependency "MDFInternationalization"
     component.dependency "MaterialComponents/private/Math"
+
+    component.test_spec 'tests' do |tests|
+      tests.test_spec 'unit' do |unit_tests|
+        unit_tests.source_files = "components/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+        unit_tests.resources = "components/#{component.base_name}/tests/unit/resources/*"
+      end
+    end
   end
 
   # MaskedTransition
@@ -619,6 +765,13 @@
     component.dependency "MotionTransitioning", "~> 5.0"
     component.dependency "MotionAnimator", "~> 2.0"
     component.dependency "MotionInterchange", "~> 1.0"
+
+    component.test_spec 'tests' do |tests|
+      tests.test_spec 'unit' do |unit_tests|
+        unit_tests.source_files = "components/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+        unit_tests.resources = "components/#{component.base_name}/tests/unit/resources/*"
+      end
+    end
   end
 
   # NavigationBar
@@ -635,6 +788,13 @@
     component.dependency "MaterialComponents/Typography"
     component.dependency "MDFInternationalization"
     component.dependency "MaterialComponents/private/Math"
+
+    component.test_spec 'tests' do |tests|
+      tests.test_spec 'unit' do |unit_tests|
+        unit_tests.source_files = "components/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+        unit_tests.resources = "components/#{component.base_name}/tests/unit/resources/*"
+      end
+    end
   end
 
   mdc.subspec "NavigationBar+ColorThemer" do |extension|
@@ -663,6 +823,13 @@
     component.source_files = "components/#{component.base_name}/src/*.{h,m}", "components/#{component.base_name}/src/private/*.{h,m}"
 
     component.dependency "MaterialComponents/private/Application"
+
+    component.test_spec 'tests' do |tests|
+      tests.test_spec 'unit' do |unit_tests|
+        unit_tests.source_files = "components/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+        unit_tests.resources = "components/#{component.base_name}/tests/unit/resources/*"
+      end
+    end
   end
 
   # PageControl
@@ -672,6 +839,13 @@
     component.public_header_files = "components/#{component.base_name}/src/*.h"
     component.source_files = "components/#{component.base_name}/src/*.{h,m}", "components/#{component.base_name}/src/private/*.{h,m}"
     component.resources = ["components/#{component.base_name}/src/Material#{component.base_name}.bundle"]
+
+    component.test_spec 'tests' do |tests|
+      tests.test_spec 'unit' do |unit_tests|
+        unit_tests.source_files = "components/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+        unit_tests.resources = "components/#{component.base_name}/tests/unit/resources/*"
+      end
+    end
   end
 
   mdc.subspec "PageControl+ColorThemer" do |extension|
@@ -689,6 +863,13 @@
     component.ios.deployment_target = '8.0'
     component.public_header_files = "components/#{component.base_name}/src/*.h"
     component.source_files = "components/#{component.base_name}/src/*.{h,m}", "components/#{component.base_name}/src/private/*.{h,m}"
+
+    component.test_spec 'tests' do |tests|
+      tests.test_spec 'unit' do |unit_tests|
+        unit_tests.source_files = "components/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+        unit_tests.resources = "components/#{component.base_name}/tests/unit/resources/*"
+      end
+    end
   end
 
   # ProgressView
@@ -702,6 +883,13 @@
     component.dependency "MaterialComponents/Palettes"
     component.dependency "MaterialComponents/private/Math"
     component.dependency "MotionAnimator", "~> 2.1"
+
+    component.test_spec 'tests' do |tests|
+      tests.test_spec 'unit' do |unit_tests|
+        unit_tests.source_files = "components/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+        unit_tests.resources = "components/#{component.base_name}/tests/unit/resources/*"
+      end
+    end
   end
 
   mdc.subspec "ProgressView+ColorThemer" do |extension|
@@ -719,6 +907,13 @@
     component.ios.deployment_target = '8.0'
     component.public_header_files = "components/#{component.base_name}/src/*.h"
     component.source_files = "components/#{component.base_name}/src/*.{h,m}"
+
+    component.test_spec 'tests' do |tests|
+      tests.test_spec 'unit' do |unit_tests|
+        unit_tests.source_files = "components/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+        unit_tests.resources = "components/#{component.base_name}/tests/unit/resources/*"
+      end
+    end
   end
 
   # ShadowLayer
@@ -729,6 +924,13 @@
     component.source_files = "components/#{component.base_name}/src/*.{h,m}"
 
     component.dependency "MaterialComponents/ShadowElevations"
+
+    component.test_spec 'tests' do |tests|
+      tests.test_spec 'unit' do |unit_tests|
+        unit_tests.source_files = "components/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+        unit_tests.resources = "components/#{component.base_name}/tests/unit/resources/*"
+      end
+    end
   end
 
   # Slider
@@ -741,6 +943,13 @@
     component.dependency "MaterialComponents/Palettes"
     component.dependency "MaterialComponents/ShadowElevations"
     component.dependency "MaterialComponents/private/ThumbTrack"
+
+    component.test_spec 'tests' do |tests|
+      tests.test_spec 'unit' do |unit_tests|
+        unit_tests.source_files = "components/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+        unit_tests.resources = "components/#{component.base_name}/tests/unit/resources/*"
+      end
+    end
   end
 
   mdc.subspec "Slider+ColorThemer" do |extension|
@@ -768,6 +977,13 @@
     component.dependency "MaterialComponents/private/Application"
     component.dependency "MaterialComponents/private/KeyboardWatcher"
     component.dependency "MaterialComponents/private/Overlay"
+
+    component.test_spec 'tests' do |tests|
+      tests.test_spec 'unit' do |unit_tests|
+        unit_tests.source_files = "components/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+        unit_tests.resources = "components/#{component.base_name}/tests/unit/resources/*"
+      end
+    end
   end
 
   mdc.subspec "Snackbar+ColorThemer" do |extension|
@@ -812,6 +1028,13 @@
     component.dependency "MaterialComponents/ShadowLayer"
     component.dependency "MaterialComponents/Typography"
     component.dependency "MaterialComponents/private/Math"
+
+    component.test_spec 'tests' do |tests|
+      tests.test_spec 'unit' do |unit_tests|
+        unit_tests.source_files = "components/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+        unit_tests.resources = "components/#{component.base_name}/tests/unit/resources/*"
+      end
+    end
   end
 
   mdc.subspec "Tabs+ColorThemer" do |extension|
@@ -854,6 +1077,13 @@
     component.dependency "MDFInternationalization"
     component.dependency "MaterialComponents/private/Math"
     component.dependency "MDFInternationalization"
+
+    component.test_spec 'tests' do |tests|
+      tests.test_spec 'unit' do |unit_tests|
+        unit_tests.source_files = "components/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+        unit_tests.resources = "components/#{component.base_name}/tests/unit/resources/*"
+      end
+    end
   end
 
   mdc.subspec "TextFields+ColorThemer" do |extension|
@@ -892,6 +1122,13 @@
 
     component.dependency "MaterialComponents/schemes/Color"
     component.dependency "MaterialComponents/schemes/Typography"
+
+    component.test_spec 'tests' do |tests|
+      tests.test_spec 'unit' do |unit_tests|
+        unit_tests.source_files = "components/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+        unit_tests.resources = "components/#{component.base_name}/tests/unit/resources/*"
+      end
+    end
   end
 
   # Typography
@@ -903,6 +1140,13 @@
 
     component.dependency "MaterialComponents/private/Application"
     component.dependency "MaterialComponents/private/Math"
+
+    component.test_spec 'tests' do |tests|
+      tests.test_spec 'unit' do |unit_tests|
+        unit_tests.source_files = "components/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+        unit_tests.resources = "components/#{component.base_name}/tests/unit/resources/*"
+      end
+    end
   end
 
   mdc.subspec "schemes" do |scheme_spec|
@@ -910,6 +1154,13 @@
       scheme.ios.deployment_target = '8.0'
       scheme.public_header_files = "components/schemes/#{scheme.base_name}/src/*.h"
       scheme.source_files = "components/schemes/#{scheme.base_name}/src/*.{h,m}"
+
+      scheme.test_spec 'tests' do |tests|
+        tests.test_spec 'unit' do |unit_tests|
+          unit_tests.source_files = "components/schemes/#{scheme.base_name}/tests/unit/*.{h,m,swift}", "components/schemes/#{scheme.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+          unit_tests.resources = "components/schemes/#{scheme.base_name}/tests/unit/resources/*"
+        end
+      end
     end
     scheme_spec.subspec "Shape" do |scheme|
       scheme.ios.deployment_target = '8.0'
@@ -917,11 +1168,25 @@
       scheme.source_files = "components/schemes/#{scheme.base_name}/src/*.{h,m}"
       scheme.dependency "MaterialComponents/private/ShapeLibrary"
       scheme.dependency "MaterialComponents/private/Shapes"
+
+      scheme.test_spec 'tests' do |tests|
+        tests.test_spec 'unit' do |unit_tests|
+          unit_tests.source_files = "components/schemes/#{scheme.base_name}/tests/unit/*.{h,m,swift}", "components/schemes/#{scheme.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+          unit_tests.resources = "components/schemes/#{scheme.base_name}/tests/unit/resources/*"
+        end
+      end
     end
     scheme_spec.subspec "Typography" do |scheme|
       scheme.ios.deployment_target = '8.0'
       scheme.public_header_files = "components/schemes/#{scheme.base_name}/src/*.h"
       scheme.source_files = "components/schemes/#{scheme.base_name}/src/*.{h,m}"
+
+      scheme.test_spec 'tests' do |tests|
+        tests.test_spec 'unit' do |unit_tests|
+          unit_tests.source_files = "components/schemes/#{scheme.base_name}/tests/unit/*.{h,m,swift}", "components/schemes/#{scheme.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+          unit_tests.resources = "components/schemes/#{scheme.base_name}/tests/unit/resources/*"
+        end
+      end
     end
   end
 
@@ -935,6 +1200,13 @@
       component.ios.deployment_target = '8.0'
       component.public_header_files = "components/private/#{component.base_name}/src/*.h"
       component.source_files = "components/private/#{component.base_name}/src/*.{h,m}"
+
+      component.test_spec 'tests' do |tests|
+        tests.test_spec 'unit' do |unit_tests|
+          unit_tests.source_files = "components/private/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/private/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+          unit_tests.resources = "components/private/#{component.base_name}/tests/unit/resources/*"
+        end
+      end
     end
 
     private_spec.subspec "KeyboardWatcher" do |component|
@@ -943,18 +1215,39 @@
       component.source_files = "components/private/#{component.base_name}/src/*.{h,m}"
 
       component.dependency "MaterialComponents/private/Application"
+
+      component.test_spec 'tests' do |tests|
+        tests.test_spec 'unit' do |unit_tests|
+          unit_tests.source_files = "components/private/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/private/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+          unit_tests.resources = "components/private/#{component.base_name}/tests/unit/resources/*"
+        end
+      end
     end
 
     private_spec.subspec "Math" do |component|
       component.ios.deployment_target = '8.0'
       component.public_header_files = "components/private/#{component.base_name}/src/*.h"
       component.source_files = "components/private/#{component.base_name}/src/*.{h,m}"
+
+      component.test_spec 'tests' do |tests|
+        tests.test_spec 'unit' do |unit_tests|
+          unit_tests.source_files = "components/private/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/private/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+          unit_tests.resources = "components/private/#{component.base_name}/tests/unit/resources/*"
+        end
+      end
     end
 
     private_spec.subspec "Overlay" do |component|
       component.ios.deployment_target = '8.0'
       component.public_header_files = "components/private/#{component.base_name}/src/*.h"
       component.source_files = "components/private/#{component.base_name}/src/*.{h,m}", "components/private/#{component.base_name}/src/private/*.{h,m}"
+
+      component.test_spec 'tests' do |tests|
+        tests.test_spec 'unit' do |unit_tests|
+          unit_tests.source_files = "components/private/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/private/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+          unit_tests.resources = "components/private/#{component.base_name}/tests/unit/resources/*"
+        end
+      end
     end
 
     private_spec.subspec "ShapeLibrary" do |component|
@@ -964,6 +1257,13 @@
 
       component.dependency "MaterialComponents/private/Shapes"
       component.dependency "MaterialComponents/private/Math"
+
+      component.test_spec 'tests' do |tests|
+        tests.test_spec 'unit' do |unit_tests|
+          unit_tests.source_files = "components/private/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/private/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+          unit_tests.resources = "components/private/#{component.base_name}/tests/unit/resources/*"
+        end
+      end
     end
 
     private_spec.subspec "Shapes" do |component|
@@ -973,6 +1273,13 @@
 
       component.dependency "MaterialComponents/ShadowLayer"
       component.dependency "MaterialComponents/private/Math"
+
+      component.test_spec 'tests' do |tests|
+        tests.test_spec 'unit' do |unit_tests|
+          unit_tests.source_files = "components/private/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/private/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+          unit_tests.resources = "components/private/#{component.base_name}/tests/unit/resources/*"
+        end
+      end
     end
 
     private_spec.subspec "ThumbTrack" do |component|
@@ -986,6 +1293,13 @@
       component.dependency "MaterialComponents/Typography"
       component.dependency "MDFInternationalization"
       component.dependency "MaterialComponents/private/Math"
+
+      component.test_spec 'tests' do |tests|
+        tests.test_spec 'unit' do |unit_tests|
+          unit_tests.source_files = "components/private/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/private/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+          unit_tests.resources = "components/private/#{component.base_name}/tests/unit/resources/*"
+        end
+      end
     end
 
     private_spec.subspec "UIMetrics" do |component|
@@ -994,6 +1308,13 @@
       component.source_files = "components/private/#{component.base_name}/src/*.{h,m}", "components/private/#{component.base_name}/src/private/*.{h,m}"
 
       component.dependency "MaterialComponents/private/Application"
+
+      component.test_spec 'tests' do |tests|
+        tests.test_spec 'unit' do |unit_tests|
+          unit_tests.source_files = "components/private/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/private/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+          unit_tests.resources = "components/private/#{component.base_name}/tests/unit/resources/*"
+        end
+      end
     end
   end
 end
diff --git a/MaterialComponentsAlpha.podspec b/MaterialComponentsAlpha.podspec
index 53ddffe..d1748ad 100644
--- a/MaterialComponentsAlpha.podspec
+++ b/MaterialComponentsAlpha.podspec
@@ -1,6 +1,6 @@
 Pod::Spec.new do |mdc|
   mdc.name         = "MaterialComponentsAlpha"
-  mdc.version      = "64.0.0"
+  mdc.version      = "65.0.0"
   mdc.authors      = "The Material Components authors."
   mdc.summary      = "A collection of stand-alone alpha UI libraries that are not yet guaranteed to be ready for general production use. Use with caution."
   mdc.homepage     = "https://github.com/material-components/material-components-ios"
@@ -23,6 +23,20 @@
     component.dependency "MaterialComponents/BottomSheet"
     component.dependency "MaterialComponents/Ink"
     component.dependency "MaterialComponents/Typography"
+
+    component.test_spec 'tests' do |tests|
+      tests.test_spec 'unit' do |unit_tests|
+        unit_tests.source_files = "components/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+      end
+    end
+  end
+
+  mdc.subspec "ActionSheet+ColorThemer" do |extension|
+    extension.ios.deployment_target = '8.0'
+    extension.public_header_files = "components/#{extension.base_name.split('+')[0]}/src/#{extension.base_name.split('+')[1]}/*.h"
+    extension.source_files = "components/#{extension.base_name.split('+')[0]}/src/#{extension.base_name.split('+')[1]}/*.{h,m}", "components/#{extension.base_name.split('+')[0]}/src/#{extension.base_name.split('+')[1]}/private/*.{h,m}"
+    extension.dependency "MaterialComponentsAlpha/#{extension.base_name.split('+')[0]}"
+    extension.dependency "MaterialComponents/schemes/Color"
   end
 
   mdc.subspec "ActionSheet+TypographyThemer" do |extension|
@@ -42,6 +56,12 @@
 
     component.dependency "MaterialComponents/ShadowLayer"
     component.dependency "MaterialComponents/private/UIMetrics"
+
+    component.test_spec 'tests' do |tests|
+      tests.test_spec 'unit' do |unit_tests|
+        unit_tests.source_files = "components/#{component.base_name}/tests/unit/*.{h,m,swift}", "components/#{component.base_name}/tests/unit/supplemental/*.{h,m,swift}"
+      end
+    end
   end
 
   mdc.subspec "private" do |private_spec|
diff --git a/MaterialComponentsEarlGreyTests.podspec b/MaterialComponentsEarlGreyTests.podspec
index f3e1027..093775e 100644
--- a/MaterialComponentsEarlGreyTests.podspec
+++ b/MaterialComponentsEarlGreyTests.podspec
@@ -1,6 +1,6 @@
 Pod::Spec.new do |s|
   s.name         = "MaterialComponentsEarlGreyTests"
-  s.version      = "64.0.0"
+  s.version      = "65.0.0"
   s.authors      = "The Material Components authors."
   s.summary      = "This spec is an aggregate of all the Material Components EarlGrey tests."
   s.description  = "This spec is made for use in the MDC Catalog."
diff --git a/MaterialComponentsExamples.podspec b/MaterialComponentsExamples.podspec
index 67eae12..cf0fca7 100644
--- a/MaterialComponentsExamples.podspec
+++ b/MaterialComponentsExamples.podspec
@@ -1,6 +1,6 @@
 Pod::Spec.new do |s|
   s.name         = "MaterialComponentsExamples"
-  s.version      = "64.0.0"
+  s.version      = "65.0.0"
   s.authors      = "The Material Components authors."
   s.summary      = "This spec is an aggregate of all the Material Components examples."
   s.description  = "This spec is made for use in the MDC Catalog. Used in conjunction with CatalogByConvention we create our Material Catalog."
diff --git a/MaterialComponentsUnitTests.podspec b/MaterialComponentsUnitTests.podspec
deleted file mode 100644
index 465ee33..0000000
--- a/MaterialComponentsUnitTests.podspec
+++ /dev/null
@@ -1,18 +0,0 @@
-Pod::Spec.new do |s|
-  s.name         = "MaterialComponentsUnitTests"
-  s.version      = "64.0.0"
-  s.authors      = "The Material Components authors."
-  s.summary      = "This spec is an aggregate of all the Material Components unit tests."
-  s.description  = "This spec is made for use in the MDC Catalog."
-  s.homepage     = "https://github.com/material-components/material-components-ios"
-  s.license      = 'Apache 2.0'
-  s.source       = { :git => "https://github.com/material-components/material-components-ios.git", :tag => "v#{s.version}" }
-  s.platform     = :ios, '8.0'
-  s.requires_arc = true
-  s.source_files = 'components/*/tests/unit/*.{h,m,swift}', 'components/private/*/tests/unit/*.{h,m,swift}', 'components/*/tests/unit/supplemental/*.{h,m,swift}', 'components/private/*/tests/unit/supplemental/*.{h,m,swift}', 'components/schemes/*/tests/unit/*.{h,m,swift}'
-  s.resources = ['components/*/tests/unit/resources/*', 'components/private/*/tests/unit/resources/*']
-  s.framework    = 'XCTest'
-  s.dependency 'MaterialComponents'
-  s.dependency 'MaterialComponentsAlpha'
-  s.dependency 'MDFTextAccessibility'
-end
diff --git a/VERSION b/VERSION
index b00ad46..4acff0a 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-64.0.0
+65.0.0
diff --git a/catalog/MDCCatalog.xcodeproj/xcshareddata/xcschemes/MDCCatalog.xcscheme b/catalog/MDCCatalog.xcodeproj/xcshareddata/xcschemes/MDCCatalog.xcscheme
index ae52354..a5b8dd6 100644
--- a/catalog/MDCCatalog.xcodeproj/xcshareddata/xcschemes/MDCCatalog.xcscheme
+++ b/catalog/MDCCatalog.xcodeproj/xcshareddata/xcschemes/MDCCatalog.xcscheme
@@ -33,10 +33,20 @@
             skipped = "NO">
             <BuildableReference
                BuildableIdentifier = "primary"
-               BlueprintIdentifier = "66CB712B1C853DB30099B932"
-               BuildableName = "MDCUnitTests.xctest"
-               BlueprintName = "MDCUnitTests"
-               ReferencedContainer = "container:MDCUnitTests.xcodeproj">
+               BlueprintIdentifier = "153B950E9F5C9E9E4BE2D402CB52E43A"
+               BuildableName = "MaterialComponents-Unit-Tests.xctest"
+               BlueprintName = "MaterialComponents-Unit-Tests"
+               ReferencedContainer = "container:Pods/Pods.xcodeproj">
+            </BuildableReference>
+         </TestableReference>
+         <TestableReference
+            skipped = "NO">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "47FB08CD9CD5B00DEC8D9A84BCFD9232"
+               BuildableName = "MaterialComponentsAlpha-Unit-Tests.xctest"
+               BlueprintName = "MaterialComponentsAlpha-Unit-Tests"
+               ReferencedContainer = "container:Pods/Pods.xcodeproj">
             </BuildableReference>
          </TestableReference>
       </Testables>
diff --git a/catalog/MDCCatalog.xcworkspace/contents.xcworkspacedata b/catalog/MDCCatalog.xcworkspace/contents.xcworkspacedata
index db6c3fc..dca7a84 100644
--- a/catalog/MDCCatalog.xcworkspace/contents.xcworkspacedata
+++ b/catalog/MDCCatalog.xcworkspace/contents.xcworkspacedata
@@ -5,9 +5,6 @@
       location = "group:MDCCatalog.xcodeproj">
    </FileRef>
    <FileRef
-      location = "group:MDCUnitTests.xcodeproj">
-   </FileRef>
-   <FileRef
       location = "group:MDCDragons.xcodeproj">
    </FileRef>
    <FileRef
diff --git a/catalog/MDCCatalog/Info.plist b/catalog/MDCCatalog/Info.plist
index a41397a..1210d07 100644
--- a/catalog/MDCCatalog/Info.plist
+++ b/catalog/MDCCatalog/Info.plist
@@ -15,7 +15,7 @@
 	<key>CFBundlePackageType</key>
 	<string>APPL</string>
 	<key>CFBundleShortVersionString</key>
-	<string>64.0.0</string>
+	<string>65.0.0</string>
 	<key>CFBundleSignature</key>
 	<string>????</string>
 	<key>CFBundleVersion</key>
diff --git a/catalog/MDCCatalog/MDCThemePickerViewController.swift b/catalog/MDCCatalog/MDCThemePickerViewController.swift
index 5cc24fd..9c355f8 100644
--- a/catalog/MDCCatalog/MDCThemePickerViewController.swift
+++ b/catalog/MDCCatalog/MDCThemePickerViewController.swift
@@ -57,9 +57,13 @@
 class MDCThemePickerViewController: UIViewController, UICollectionViewDataSource,
   UICollectionViewDelegateFlowLayout {
 
-  let paletteTitle = UILabel()
   let palettesCollectionView = UICollectionView(frame: .zero,
                                                 collectionViewLayout: UICollectionViewFlowLayout())
+
+  private var collectionViewLayout: UICollectionViewFlowLayout {
+    return palettesCollectionView.collectionViewLayout as! UICollectionViewFlowLayout
+  }
+
   let titleColor = AppTheme.globalTheme.colorScheme.onSurfaceColor.withAlphaComponent(0.5)
   let titleFont = AppTheme.globalTheme.typographyScheme.button
   private let cellReuseIdentifier = "cell"
@@ -103,6 +107,7 @@
 
   override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
     super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
+
   }
 
   required init?(coder aDecoder: NSCoder) {
@@ -112,67 +117,39 @@
   override func viewDidLoad() {
     super.viewDidLoad()
 
-    paletteTitle.text = "Material Palette-based themes"
-    paletteTitle.font = titleFont
-    paletteTitle.textColor = titleColor
-    paletteTitle.translatesAutoresizingMaskIntoConstraints = false
-    view.addSubview(paletteTitle)
-    view.addConstraint(NSLayoutConstraint(item: paletteTitle,
-                                          attribute: .bottom,
-                                          relatedBy: .equal,
-                                          toItem: self.view,
-                                          attribute: .top,
-                                          multiplier: 1.0,
-                                          constant: 36))
-    view.addConstraint(NSLayoutConstraint(item: paletteTitle,
-                                          attribute: .left,
-                                          relatedBy: .equal,
-                                          toItem: self.view,
-                                          attribute: .left,
-                                          multiplier: 1.0,
-                                          constant: 16))
+    title = "Material Palette-based themes"
+    view.backgroundColor = .white
+    setUpCollectionView()
+  }
 
+  override func viewDidLayoutSubviews() {
+    super.viewDidLayoutSubviews()
+
+    positionCollectionView()
+  }
+
+  func setUpCollectionView() {
     palettesCollectionView.register(PaletteCell.self,
                                     forCellWithReuseIdentifier: cellReuseIdentifier)
     palettesCollectionView.translatesAutoresizingMaskIntoConstraints = false
     palettesCollectionView.delegate = self
     palettesCollectionView.dataSource = self
     palettesCollectionView.backgroundColor = .white
-    palettesCollectionView.contentInset = UIEdgeInsets(top: 0, left: 8, bottom: 0, right: 0)
     view.addSubview(palettesCollectionView)
-    let rowWidth = view.bounds.width - cellSpacing * 2
-    let cellsPerRow = floor(rowWidth / (cellSize + cellSpacing))
-    let numberOfCells = CGFloat(colorSchemeConfigurations.count)
-    let numberOfRows = ceil(numberOfCells / cellsPerRow)
-    view.addConstraint(NSLayoutConstraint(item: palettesCollectionView,
-                                          attribute: .left,
-                                          relatedBy: .equal,
-                                          toItem: self.view,
-                                          attribute: .left,
-                                          multiplier: 1,
-                                          constant: 0))
-    view.addConstraint(NSLayoutConstraint(item: palettesCollectionView,
-                                          attribute: .right,
-                                          relatedBy: .equal,
-                                          toItem: self.view,
-                                          attribute: .right,
-                                          multiplier: 1,
-                                          constant: 0))
-    view.addConstraint(NSLayoutConstraint(item: palettesCollectionView,
-                                          attribute: .top,
-                                          relatedBy: .equal,
-                                          toItem: self.paletteTitle,
-                                          attribute: .bottom,
-                                          multiplier: 1,
-                                          constant: 10))
-    view.addConstraint(NSLayoutConstraint(item: palettesCollectionView,
-                                          attribute: .height,
-                                          relatedBy: .equal,
-                                          toItem: nil,
-                                          attribute: .notAnAttribute,
-                                          multiplier: 1,
-                                          constant: numberOfRows * (cellSize + (cellSpacing * 2))))
-    view.backgroundColor = .white
+  }
+
+  func positionCollectionView() {
+    var originX = view.bounds.origin.x
+    var width = view.bounds.size.width
+    var height = view.bounds.size.height
+    if #available(iOS 11.0, *) {
+      originX += view.safeAreaInsets.left;
+      width -= (view.safeAreaInsets.left + view.safeAreaInsets.right);
+      height -= (view.safeAreaInsets.top + view.safeAreaInsets.bottom);
+    }
+    let frame = CGRect(x: originX, y: view.bounds.origin.y, width: width, height: height)
+    palettesCollectionView.frame = frame
+    palettesCollectionView.collectionViewLayout.invalidateLayout()
   }
 
   func collectionView(_ collectionView: UICollectionView,
@@ -248,6 +225,7 @@
 
   override init(frame: CGRect) {
     super.init(frame: frame)
+
     imageView.image = MDCIcons.imageFor_ic_check()?.withRenderingMode(.alwaysTemplate)
     imageView.tintColor = .white
     imageView.contentMode = .center
diff --git a/catalog/MDCDragons.xcodeproj/xcshareddata/xcschemes/MDCDragons.xcscheme b/catalog/MDCDragons.xcodeproj/xcshareddata/xcschemes/MDCDragons.xcscheme
index 3572609..77128f6 100644
--- a/catalog/MDCDragons.xcodeproj/xcshareddata/xcschemes/MDCDragons.xcscheme
+++ b/catalog/MDCDragons.xcodeproj/xcshareddata/xcschemes/MDCDragons.xcscheme
@@ -32,10 +32,20 @@
             skipped = "NO">
             <BuildableReference
                BuildableIdentifier = "primary"
-               BlueprintIdentifier = "66CB712B1C853DB30099B932"
-               BuildableName = "MDCUnitTests.xctest"
-               BlueprintName = "MDCUnitTests"
-               ReferencedContainer = "container:MDCUnitTests.xcodeproj">
+               BlueprintIdentifier = "153B950E9F5C9E9E4BE2D402CB52E43A"
+               BuildableName = "MaterialComponents-Unit-Tests.xctest"
+               BlueprintName = "MaterialComponents-Unit-Tests"
+               ReferencedContainer = "container:Pods/Pods.xcodeproj">
+            </BuildableReference>
+         </TestableReference>
+         <TestableReference
+            skipped = "NO">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "47FB08CD9CD5B00DEC8D9A84BCFD9232"
+               BuildableName = "MaterialComponentsAlpha-Unit-Tests.xctest"
+               BlueprintName = "MaterialComponentsAlpha-Unit-Tests"
+               ReferencedContainer = "container:Pods/Pods.xcodeproj">
             </BuildableReference>
          </TestableReference>
       </Testables>
diff --git a/catalog/MDCDragons/MDCDragonsController.swift b/catalog/MDCDragons/MDCDragonsController.swift
index c16f9c5..14fb689 100644
--- a/catalog/MDCDragons/MDCDragonsController.swift
+++ b/catalog/MDCDragons/MDCDragonsController.swift
@@ -1,12 +1,12 @@
 /*
  Copyright 2015-present the Material Components for iOS authors. All Rights Reserved.
- 
+
  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at
- 
+
  http://www.apache.org/licenses/LICENSE-2.0
- 
+
  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -30,7 +30,7 @@
                             UITableViewDataSource,
                             UISearchBarDelegate,
                             UIGestureRecognizerDelegate {
-  
+
   fileprivate struct Constants {
     static let headerScrollThreshold: CGFloat = 50
     static let headerViewMaxHeight: CGFloat = 113
@@ -45,8 +45,11 @@
   fileprivate var results: [DragonCell]!
   fileprivate var tableView: UITableView!
   fileprivate var isSearchActive = false
-  
-  fileprivate lazy var headerViewController = MDCFlexibleHeaderViewController()
+
+  fileprivate var headerViewController = MDCFlexibleHeaderViewController()
+
+  private let keyboardWatcher = MDCKeyboardWatcher()
+
   var headerView: HeaderView!
 
   init(node: CBCNode) {
@@ -58,25 +61,31 @@
     super.init(nibName: nil, bundle: nil)
     results = getLeafNodes(node: node)
     searched = results
+
+    setUpKeyboardWatcher()
   }
-  
+
+  deinit {
+    NotificationCenter.default.removeObserver(self)
+  }
+
   func getLeafNodes(node: CBCNode) -> [DragonCell] {
     if node.children.count == 0 {
       return [DragonCell(node: node)]
     }
-    
+
     var cells = [DragonCell]()
     for child in node.children {
       cells += getLeafNodes(node: child)
     }
-    
+
     return cells
   }
 
   required init?(coder aDecoder: NSCoder) {
     fatalError("init(coder:) has not been implemented")
   }
-  
+
   override func viewDidLoad() {
     super.viewDidLoad()
     title = "Material Dragons"
@@ -120,17 +129,17 @@
       }
     #endif
   }
-  
+
   func preiOS11Constraints() {
     tableView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
   }
-  
+
   func setupHeaderView() {
     headerView = HeaderView(frame: headerViewController.headerView.bounds)
     headerView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
     headerView.title.text = title!
     headerView.searchBar.delegate = self
-    
+
     headerViewController.headerView.addSubview(headerView)
     headerViewController.headerView.forwardTouchEvents(for: headerView)
     headerViewController.headerView.backgroundColor = Constants.headerColor
@@ -143,24 +152,24 @@
     let offset = scrollView.contentOffset.y
     let inset = scrollView.contentInset.top
     let relativeOffset = inset + offset
-    
+
     headerView.imageView.alpha = 1 - (relativeOffset / Constants.headerScrollThreshold)
     headerView.title.alpha = 1 - (relativeOffset / Constants.headerScrollThreshold)
   }
-  
+
   override func viewWillAppear(_ animated: Bool) {
     super.viewWillAppear(animated)
     navigationController?.setNavigationBarHidden(true, animated: animated)
   }
-  
+
   override var childViewControllerForStatusBarStyle: UIViewController? {
     return headerViewController
   }
-  
+
   override var childViewControllerForStatusBarHidden: UIViewController? {
     return headerViewController
   }
-  
+
   // MARK: UITableViewDataSource
   func numberOfSections(in tableView: UITableView) -> Int {
     return isSearchActive ? 1 : 2
@@ -173,7 +182,7 @@
   func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
     return isSearchActive ? searched.count : cellsBySection[section].count
   }
-  
+
   // MARK: UITableViewDelegate
   func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
     guard let cell =
@@ -231,7 +240,7 @@
       nodeData.expanded = !nodeData.expanded
     }
   }
-  
+
   func setupTransition(nodeData: DragonCell) {
     var vc = nodeData.node.createExampleViewController()
     if !vc.responds(to: NSSelectorFromString("catalogShouldHideNavigation")) {
@@ -243,7 +252,7 @@
           NSFontAttributeName: UIFont.systemFont(ofSize: 16) ]
       container.isTopLayoutGuideAdjustmentEnabled = true
       vc.title = nodeData.node.title
-      
+
       let headerView = container.appBar.headerViewController.headerView
       if let collectionVC = vc as? UICollectionViewController {
         headerView.trackingScrollView = collectionVC.collectionView
@@ -254,32 +263,32 @@
     }
     self.navigationController?.pushViewController(vc, animated: true)
   }
-  
+
 }
 
 // UIScrollViewDelegate
 extension MDCDragonsController {
-  
+
   func scrollViewDidScroll(_ scrollView: UIScrollView) {
     if scrollView == headerViewController.headerView.trackingScrollView {
       self.headerViewController.headerView.trackingScrollDidScroll()
       self.adjustLogoForScrollView(scrollView)
     }
   }
-  
+
   func scrollViewDidEndDragging( _ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
     let headerView = headerViewController.headerView
     if scrollView == headerView.trackingScrollView {
       headerView.trackingScrollDidEndDraggingWillDecelerate(decelerate)
     }
   }
-  
+
   func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
     if scrollView == headerViewController.headerView.trackingScrollView {
       self.headerViewController.headerView.trackingScrollDidEndDecelerating()
     }
   }
-  
+
   func scrollViewWillEndDragging(_ scrollView: UIScrollView,
                                           withVelocity velocity: CGPoint,
                                           targetContentOffset: UnsafeMutablePointer<CGPoint>) {
@@ -294,7 +303,7 @@
 
 // UISearchBarDelegate
 extension MDCDragonsController {
-  
+
   func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
     if searchText.isEmpty {
       isSearchActive = false
@@ -307,12 +316,12 @@
     }
     tableView.reloadData()
   }
-  
+
   func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
     searched = results
     tableView.reloadData()
   }
-  
+
   func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
     searchBar.endEditing(true)
   }
@@ -327,7 +336,7 @@
     isSearchActive = false
     tableView.reloadData()
   }
-  
+
   @objc(gestureRecognizer:shouldReceiveTouch:)
   func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
     if gestureRecognizer is UITapGestureRecognizer {
@@ -362,3 +371,42 @@
   }
 }
 
+extension MDCDragonsController {
+  func setUpKeyboardWatcher() {
+    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: .MDCKeyboardWatcherKeyboardWillShow, object: nil)
+    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: .MDCKeyboardWatcherKeyboardWillHide, object: nil)
+    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChangeFrame(notification:)), name: .MDCKeyboardWatcherKeyboardWillChangeFrame, object: nil)
+  }
+
+  func keyboardWillShow(notification: NSNotification) {
+    guard let userInfo = notification.userInfo else { return }
+    updateScrollViewWithKeyboardNotificationUserInfo(userInfo: userInfo)
+  }
+
+  func keyboardWillHide(notification: NSNotification) {
+    guard let userInfo = notification.userInfo else { return }
+    updateScrollViewWithKeyboardNotificationUserInfo(userInfo: userInfo)
+  }
+
+  func keyboardWillChangeFrame(notification: NSNotification) {
+    guard let userInfo = notification.userInfo else { return }
+    updateScrollViewWithKeyboardNotificationUserInfo(userInfo: userInfo)
+  }
+
+  func updateScrollViewWithKeyboardNotificationUserInfo(userInfo: [AnyHashable: Any]) {
+    guard let endFrame = userInfo[AnyHashable("UIKeyboardFrameEndUserInfoKey")] as? CGRect
+      else { return }
+    let endKeyboardFrameOriginInWindow = view.convert(endFrame.origin, from: nil)
+    let tableViewMaxY = tableView.frame.maxY
+    let baseInset = tableViewMaxY - endKeyboardFrameOriginInWindow.y
+    let scrollIndicatorInset = baseInset
+    var contentInset = baseInset
+    if #available(iOS 11, *) {
+      if endKeyboardFrameOriginInWindow.y < tableViewMaxY {
+        contentInset -= view.safeAreaInsets.bottom
+      }
+    }
+    tableView.contentInset.bottom = contentInset
+    tableView.scrollIndicatorInsets.bottom = scrollIndicatorInset
+  }
+}
diff --git a/catalog/MDCUnitTests.xcodeproj/project.pbxproj b/catalog/MDCUnitTests.xcodeproj/project.pbxproj
deleted file mode 100644
index 4c3364b..0000000
--- a/catalog/MDCUnitTests.xcodeproj/project.pbxproj
+++ /dev/null
@@ -1,360 +0,0 @@
-// !$*UTF8*$!
-{
-	archiveVersion = 1;
-	classes = {
-	};
-	objectVersion = 46;
-	objects = {
-
-/* Begin PBXBuildFile section */
-		669946631C87557B0073B529 /* XcodeCrashFix7.2.1.m in Sources */ = {isa = PBXBuildFile; fileRef = 669946621C87557B0073B529 /* XcodeCrashFix7.2.1.m */; };
-		DD46A339CC477B497F93E67E /* Pods_MDCUnitTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B10CCFA9992877A63A525E3A /* Pods_MDCUnitTests.framework */; };
-/* End PBXBuildFile section */
-
-/* Begin PBXFileReference section */
-		00F3D07F744B30C4CAC93505 /* Pods-MDCUnitTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MDCUnitTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-MDCUnitTests/Pods-MDCUnitTests.debug.xcconfig"; sourceTree = "<group>"; };
-		669946621C87557B0073B529 /* XcodeCrashFix7.2.1.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XcodeCrashFix7.2.1.m; sourceTree = "<group>"; };
-		66CB712C1C853DB30099B932 /* MDCUnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MDCUnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
-		66CB71301C853DB30099B932 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
-		9E113123E05F63397368F4AB /* Pods-MDCUnitTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MDCUnitTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-MDCUnitTests/Pods-MDCUnitTests.release.xcconfig"; sourceTree = "<group>"; };
-		B10CCFA9992877A63A525E3A /* Pods_MDCUnitTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MDCUnitTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
-/* End PBXFileReference section */
-
-/* Begin PBXFrameworksBuildPhase section */
-		66CB71291C853DB30099B932 /* Frameworks */ = {
-			isa = PBXFrameworksBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-				DD46A339CC477B497F93E67E /* Pods_MDCUnitTests.framework in Frameworks */,
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
-/* End PBXFrameworksBuildPhase section */
-
-/* Begin PBXGroup section */
-		4FEE16D1364E2A3640B8762E /* Pods */ = {
-			isa = PBXGroup;
-			children = (
-				00F3D07F744B30C4CAC93505 /* Pods-MDCUnitTests.debug.xcconfig */,
-				9E113123E05F63397368F4AB /* Pods-MDCUnitTests.release.xcconfig */,
-			);
-			name = Pods;
-			sourceTree = "<group>";
-		};
-		66CB71131C853C760099B932 = {
-			isa = PBXGroup;
-			children = (
-				66CB712D1C853DB30099B932 /* MDCUnitTests */,
-				66CB711D1C853C760099B932 /* Products */,
-				4FEE16D1364E2A3640B8762E /* Pods */,
-				D8A17A429DA1E66092E943AF /* Frameworks */,
-			);
-			sourceTree = "<group>";
-		};
-		66CB711D1C853C760099B932 /* Products */ = {
-			isa = PBXGroup;
-			children = (
-				66CB712C1C853DB30099B932 /* MDCUnitTests.xctest */,
-			);
-			name = Products;
-			sourceTree = "<group>";
-		};
-		66CB712D1C853DB30099B932 /* MDCUnitTests */ = {
-			isa = PBXGroup;
-			children = (
-				66CB71301C853DB30099B932 /* Info.plist */,
-				669946621C87557B0073B529 /* XcodeCrashFix7.2.1.m */,
-			);
-			path = MDCUnitTests;
-			sourceTree = "<group>";
-		};
-		D8A17A429DA1E66092E943AF /* Frameworks */ = {
-			isa = PBXGroup;
-			children = (
-				B10CCFA9992877A63A525E3A /* Pods_MDCUnitTests.framework */,
-			);
-			name = Frameworks;
-			sourceTree = "<group>";
-		};
-/* End PBXGroup section */
-
-/* Begin PBXNativeTarget section */
-		66CB712B1C853DB30099B932 /* MDCUnitTests */ = {
-			isa = PBXNativeTarget;
-			buildConfigurationList = 66CB71311C853DB30099B932 /* Build configuration list for PBXNativeTarget "MDCUnitTests" */;
-			buildPhases = (
-				3AAA6E9A4CDB1D9185BBE3C9 /* [CP] Check Pods Manifest.lock */,
-				66CB71281C853DB30099B932 /* Sources */,
-				66CB71291C853DB30099B932 /* Frameworks */,
-				66CB712A1C853DB30099B932 /* Resources */,
-				F9D78476FD8A80F052AA9626 /* [CP] Embed Pods Frameworks */,
-			);
-			buildRules = (
-			);
-			dependencies = (
-			);
-			name = MDCUnitTests;
-			productName = MDCUnitTests;
-			productReference = 66CB712C1C853DB30099B932 /* MDCUnitTests.xctest */;
-			productType = "com.apple.product-type.bundle.unit-test";
-		};
-/* End PBXNativeTarget section */
-
-/* Begin PBXProject section */
-		66CB71141C853C760099B932 /* Project object */ = {
-			isa = PBXProject;
-			attributes = {
-				LastUpgradeCheck = 0940;
-				ORGANIZATIONNAME = Google;
-				TargetAttributes = {
-					66CB712B1C853DB30099B932 = {
-						CreatedOnToolsVersion = 7.3;
-						LastSwiftMigration = 0810;
-					};
-				};
-			};
-			buildConfigurationList = 66CB71171C853C760099B932 /* Build configuration list for PBXProject "MDCUnitTests" */;
-			compatibilityVersion = "Xcode 3.2";
-			developmentRegion = English;
-			hasScannedForEncodings = 0;
-			knownRegions = (
-				en,
-			);
-			mainGroup = 66CB71131C853C760099B932;
-			productRefGroup = 66CB711D1C853C760099B932 /* Products */;
-			projectDirPath = "";
-			projectRoot = "";
-			targets = (
-				66CB712B1C853DB30099B932 /* MDCUnitTests */,
-			);
-		};
-/* End PBXProject section */
-
-/* Begin PBXResourcesBuildPhase section */
-		66CB712A1C853DB30099B932 /* Resources */ = {
-			isa = PBXResourcesBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
-/* End PBXResourcesBuildPhase section */
-
-/* Begin PBXShellScriptBuildPhase section */
-		3AAA6E9A4CDB1D9185BBE3C9 /* [CP] Check Pods Manifest.lock */ = {
-			isa = PBXShellScriptBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-			);
-			inputPaths = (
-				"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
-				"${PODS_ROOT}/Manifest.lock",
-			);
-			name = "[CP] Check Pods Manifest.lock";
-			outputPaths = (
-				"$(DERIVED_FILE_DIR)/Pods-MDCUnitTests-checkManifestLockResult.txt",
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-			shellPath = /bin/sh;
-			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
-			showEnvVarsInLog = 0;
-		};
-		F9D78476FD8A80F052AA9626 /* [CP] Embed Pods Frameworks */ = {
-			isa = PBXShellScriptBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-			);
-			inputPaths = (
-				"${SRCROOT}/Pods/Target Support Files/Pods-MDCUnitTests/Pods-MDCUnitTests-frameworks.sh",
-				"${BUILT_PRODUCTS_DIR}/CatalogByConvention/CatalogByConvention.framework",
-				"${BUILT_PRODUCTS_DIR}/MDFInternationalization/MDFInternationalization.framework",
-				"${BUILT_PRODUCTS_DIR}/MDFTextAccessibility/MDFTextAccessibility.framework",
-				"${BUILT_PRODUCTS_DIR}/MaterialCatalog/MaterialCatalog.framework",
-				"${BUILT_PRODUCTS_DIR}/MaterialComponents/MaterialComponents.framework",
-				"${BUILT_PRODUCTS_DIR}/MaterialComponentsAlpha/MaterialComponentsAlpha.framework",
-				"${BUILT_PRODUCTS_DIR}/MotionAnimator/MotionAnimator.framework",
-				"${BUILT_PRODUCTS_DIR}/MotionInterchange/MotionInterchange.framework",
-				"${BUILT_PRODUCTS_DIR}/MotionTransitioning/MotionTransitioning.framework",
-				"${BUILT_PRODUCTS_DIR}/MaterialComponentsUnitTests/MaterialComponentsUnitTests.framework",
-			);
-			name = "[CP] Embed Pods Frameworks";
-			outputPaths = (
-				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CatalogByConvention.framework",
-				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MDFInternationalization.framework",
-				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MDFTextAccessibility.framework",
-				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MaterialCatalog.framework",
-				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MaterialComponents.framework",
-				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MaterialComponentsAlpha.framework",
-				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MotionAnimator.framework",
-				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MotionInterchange.framework",
-				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MotionTransitioning.framework",
-				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MaterialComponentsUnitTests.framework",
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-			shellPath = /bin/sh;
-			shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-MDCUnitTests/Pods-MDCUnitTests-frameworks.sh\"\n";
-			showEnvVarsInLog = 0;
-		};
-/* End PBXShellScriptBuildPhase section */
-
-/* Begin PBXSourcesBuildPhase section */
-		66CB71281C853DB30099B932 /* Sources */ = {
-			isa = PBXSourcesBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-				669946631C87557B0073B529 /* XcodeCrashFix7.2.1.m in Sources */,
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
-/* End PBXSourcesBuildPhase section */
-
-/* Begin XCBuildConfiguration section */
-		66CB71231C853C760099B932 /* Debug */ = {
-			isa = XCBuildConfiguration;
-			buildSettings = {
-				ALWAYS_SEARCH_USER_PATHS = NO;
-				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
-				CLANG_CXX_LIBRARY = "libc++";
-				CLANG_ENABLE_MODULES = YES;
-				CLANG_ENABLE_OBJC_ARC = YES;
-				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
-				CLANG_WARN_BOOL_CONVERSION = YES;
-				CLANG_WARN_COMMA = YES;
-				CLANG_WARN_CONSTANT_CONVERSION = YES;
-				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
-				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
-				CLANG_WARN_EMPTY_BODY = YES;
-				CLANG_WARN_ENUM_CONVERSION = YES;
-				CLANG_WARN_INFINITE_RECURSION = YES;
-				CLANG_WARN_INT_CONVERSION = YES;
-				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
-				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
-				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
-				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
-				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
-				CLANG_WARN_STRICT_PROTOTYPES = YES;
-				CLANG_WARN_SUSPICIOUS_MOVE = YES;
-				CLANG_WARN_UNREACHABLE_CODE = YES;
-				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
-				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
-				COPY_PHASE_STRIP = NO;
-				DEBUG_INFORMATION_FORMAT = dwarf;
-				ENABLE_STRICT_OBJC_MSGSEND = YES;
-				ENABLE_TESTABILITY = YES;
-				GCC_C_LANGUAGE_STANDARD = gnu99;
-				GCC_DYNAMIC_NO_PIC = NO;
-				GCC_NO_COMMON_BLOCKS = YES;
-				GCC_OPTIMIZATION_LEVEL = 0;
-				GCC_PREPROCESSOR_DEFINITIONS = (
-					"DEBUG=1",
-					"$(inherited)",
-				);
-				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
-				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
-				GCC_WARN_UNDECLARED_SELECTOR = YES;
-				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
-				GCC_WARN_UNUSED_FUNCTION = YES;
-				GCC_WARN_UNUSED_VARIABLE = YES;
-				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
-				MTL_ENABLE_DEBUG_INFO = YES;
-				ONLY_ACTIVE_ARCH = YES;
-				SDKROOT = iphoneos;
-			};
-			name = Debug;
-		};
-		66CB71241C853C760099B932 /* Release */ = {
-			isa = XCBuildConfiguration;
-			buildSettings = {
-				ALWAYS_SEARCH_USER_PATHS = NO;
-				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
-				CLANG_CXX_LIBRARY = "libc++";
-				CLANG_ENABLE_MODULES = YES;
-				CLANG_ENABLE_OBJC_ARC = YES;
-				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
-				CLANG_WARN_BOOL_CONVERSION = YES;
-				CLANG_WARN_COMMA = YES;
-				CLANG_WARN_CONSTANT_CONVERSION = YES;
-				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
-				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
-				CLANG_WARN_EMPTY_BODY = YES;
-				CLANG_WARN_ENUM_CONVERSION = YES;
-				CLANG_WARN_INFINITE_RECURSION = YES;
-				CLANG_WARN_INT_CONVERSION = YES;
-				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
-				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
-				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
-				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
-				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
-				CLANG_WARN_STRICT_PROTOTYPES = YES;
-				CLANG_WARN_SUSPICIOUS_MOVE = YES;
-				CLANG_WARN_UNREACHABLE_CODE = YES;
-				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
-				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
-				COPY_PHASE_STRIP = NO;
-				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-				ENABLE_NS_ASSERTIONS = NO;
-				ENABLE_STRICT_OBJC_MSGSEND = YES;
-				GCC_C_LANGUAGE_STANDARD = gnu99;
-				GCC_NO_COMMON_BLOCKS = YES;
-				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
-				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
-				GCC_WARN_UNDECLARED_SELECTOR = YES;
-				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
-				GCC_WARN_UNUSED_FUNCTION = YES;
-				GCC_WARN_UNUSED_VARIABLE = YES;
-				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
-				MTL_ENABLE_DEBUG_INFO = NO;
-				SDKROOT = iphoneos;
-				VALIDATE_PRODUCT = YES;
-			};
-			name = Release;
-		};
-		66CB71321C853DB30099B932 /* Debug */ = {
-			isa = XCBuildConfiguration;
-			baseConfigurationReference = 00F3D07F744B30C4CAC93505 /* Pods-MDCUnitTests.debug.xcconfig */;
-			buildSettings = {
-				INFOPLIST_FILE = MDCUnitTests/Info.plist;
-				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-				PRODUCT_BUNDLE_IDENTIFIER = com.google.MDCUnitTests;
-				PRODUCT_NAME = "$(TARGET_NAME)";
-				SWIFT_VERSION = 3.0;
-			};
-			name = Debug;
-		};
-		66CB71331C853DB30099B932 /* Release */ = {
-			isa = XCBuildConfiguration;
-			baseConfigurationReference = 9E113123E05F63397368F4AB /* Pods-MDCUnitTests.release.xcconfig */;
-			buildSettings = {
-				INFOPLIST_FILE = MDCUnitTests/Info.plist;
-				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
-				PRODUCT_BUNDLE_IDENTIFIER = com.google.MDCUnitTests;
-				PRODUCT_NAME = "$(TARGET_NAME)";
-				SWIFT_VERSION = 3.0;
-			};
-			name = Release;
-		};
-/* End XCBuildConfiguration section */
-
-/* Begin XCConfigurationList section */
-		66CB71171C853C760099B932 /* Build configuration list for PBXProject "MDCUnitTests" */ = {
-			isa = XCConfigurationList;
-			buildConfigurations = (
-				66CB71231C853C760099B932 /* Debug */,
-				66CB71241C853C760099B932 /* Release */,
-			);
-			defaultConfigurationIsVisible = 0;
-			defaultConfigurationName = Release;
-		};
-		66CB71311C853DB30099B932 /* Build configuration list for PBXNativeTarget "MDCUnitTests" */ = {
-			isa = XCConfigurationList;
-			buildConfigurations = (
-				66CB71321C853DB30099B932 /* Debug */,
-				66CB71331C853DB30099B932 /* Release */,
-			);
-			defaultConfigurationIsVisible = 0;
-			defaultConfigurationName = Release;
-		};
-/* End XCConfigurationList section */
-	};
-	rootObject = 66CB71141C853C760099B932 /* Project object */;
-}
diff --git a/catalog/MDCUnitTests.xcodeproj/xcshareddata/xcschemes/MDCUnitTests.xcscheme b/catalog/MDCUnitTests.xcodeproj/xcshareddata/xcschemes/MDCUnitTests.xcscheme
deleted file mode 100644
index 8e2c324..0000000
--- a/catalog/MDCUnitTests.xcodeproj/xcshareddata/xcschemes/MDCUnitTests.xcscheme
+++ /dev/null
@@ -1,56 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
-   LastUpgradeVersion = "0940"
-   version = "1.3">
-   <BuildAction
-      parallelizeBuildables = "YES"
-      buildImplicitDependencies = "YES">
-   </BuildAction>
-   <TestAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      shouldUseLaunchSchemeArgsEnv = "YES">
-      <Testables>
-         <TestableReference
-            skipped = "NO">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "66CB712B1C853DB30099B932"
-               BuildableName = "MDCUnitTests.xctest"
-               BlueprintName = "MDCUnitTests"
-               ReferencedContainer = "container:MDCUnitTests.xcodeproj">
-            </BuildableReference>
-         </TestableReference>
-      </Testables>
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </TestAction>
-   <LaunchAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      launchStyle = "0"
-      useCustomWorkingDirectory = "NO"
-      ignoresPersistentStateOnLaunch = "NO"
-      debugDocumentVersioning = "YES"
-      debugServiceExtension = "internal"
-      allowLocationSimulation = "YES">
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </LaunchAction>
-   <ProfileAction
-      buildConfiguration = "Release"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      savedToolIdentifier = ""
-      useCustomWorkingDirectory = "NO"
-      debugDocumentVersioning = "YES">
-   </ProfileAction>
-   <AnalyzeAction
-      buildConfiguration = "Debug">
-   </AnalyzeAction>
-   <ArchiveAction
-      buildConfiguration = "Release"
-      revealArchiveInOrganizer = "YES">
-   </ArchiveAction>
-</Scheme>
diff --git a/catalog/MDCUnitTests/Info.plist b/catalog/MDCUnitTests/Info.plist
deleted file mode 100644
index ba72822..0000000
--- a/catalog/MDCUnitTests/Info.plist
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-	<key>CFBundleDevelopmentRegion</key>
-	<string>en</string>
-	<key>CFBundleExecutable</key>
-	<string>$(EXECUTABLE_NAME)</string>
-	<key>CFBundleIdentifier</key>
-	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
-	<key>CFBundleInfoDictionaryVersion</key>
-	<string>6.0</string>
-	<key>CFBundleName</key>
-	<string>$(PRODUCT_NAME)</string>
-	<key>CFBundlePackageType</key>
-	<string>BNDL</string>
-	<key>CFBundleShortVersionString</key>
-	<string>1.0</string>
-	<key>CFBundleSignature</key>
-	<string>????</string>
-	<key>CFBundleVersion</key>
-	<string>1</string>
-</dict>
-</plist>
diff --git a/catalog/MDCUnitTests/XcodeCrashFix7.2.1.m b/catalog/MDCUnitTests/XcodeCrashFix7.2.1.m
deleted file mode 100644
index 2a183a0..0000000
--- a/catalog/MDCUnitTests/XcodeCrashFix7.2.1.m
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- Copyright 2015-present the Material Components for iOS authors. All Rights Reserved.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-//
-// This file is here solely to keep the simulator from crashing on Xcode Version 7.2.1 (7C1002).
-// Without this file, the following error occurs when attempting to launch the tests:
-//
-//     Test target MDCUnitTests encountered an error (Early unexpected exit, operation never
-//     finished bootstrapping - no restart will be attempted)
-//
diff --git a/catalog/MaterialCatalog/MaterialCatalog.podspec b/catalog/MaterialCatalog/MaterialCatalog.podspec
index 1430ea6..10ca897 100644
--- a/catalog/MaterialCatalog/MaterialCatalog.podspec
+++ b/catalog/MaterialCatalog/MaterialCatalog.podspec
@@ -1,6 +1,6 @@
 Pod::Spec.new do |s|
   s.name         = "MaterialCatalog"
-  s.version      = "64.0.0"
+  s.version      = "65.0.0"
   s.summary      = "Helper Objective-C classes for the MDC catalog."
   s.description  = "This spec is made for use in the MDC Catalog."
   s.homepage     = "https://github.com/material-components/material-components-ios"
diff --git a/catalog/Podfile b/catalog/Podfile
index b5923a8..11577d9 100644
--- a/catalog/Podfile
+++ b/catalog/Podfile
@@ -5,20 +5,56 @@
   platform :ios, '8.0'
   project 'MDCCatalog.xcodeproj'
   pod 'MaterialComponentsExamples', :path => '../'
-  pod 'MaterialComponents', :path => '../'
-  pod 'MaterialComponentsAlpha', :path => '../'
-  pod 'CatalogByConvention', "~> 2.5"
-  pod 'MaterialCatalog', :path => 'MaterialCatalog/'
-
-  use_frameworks!
-end
-
-target "MDCUnitTests" do
-  platform :ios, '8.0'
-  project 'MDCUnitTests.xcodeproj'
-  pod 'MaterialComponentsUnitTests', :path => '../'
-  pod 'MaterialComponents', :path => '../'
-  pod 'MaterialComponentsAlpha', :path => '../'
+  pod 'MaterialComponents', :path => '../', :testspecs => [
+    'ActivityIndicator/tests/unit',
+    'AnimationTiming/tests/unit',
+    'AppBar/tests/unit',
+    'BottomAppBar/tests/unit',
+    'BottomNavigation/tests/unit',
+    'BottomSheet/tests/unit',
+    'Buttons/tests/unit',
+    'Cards/tests/unit',
+    'Chips/tests/unit',
+    'CollectionCells/tests/unit',
+    'CollectionLayoutAttributes/tests/unit',
+    'Collections/tests/unit',
+    'Dialogs/tests/unit',
+    'FeatureHighlight/tests/unit',
+    'FlexibleHeader/tests/unit',
+    'HeaderStackView/tests/unit',
+    'Ink/tests/unit',
+    'LibraryInfo/tests/unit',
+    'List/tests/unit',
+    'MaskedTransition/tests/unit',
+    'NavigationBar/tests/unit',
+    'OverlayWindow/tests/unit',
+    'PageControl/tests/unit',
+    'Palettes/tests/unit',
+    'private/Application/tests/unit',
+    'private/KeyboardWatcher/tests/unit',
+    'private/Math/tests/unit',
+    'private/Overlay/tests/unit',
+    'private/ShapeLibrary/tests/unit',
+    'private/Shapes/tests/unit',
+    'private/ThumbTrack/tests/unit',
+    'private/UIMetrics/tests/unit',
+    'ProgressView/tests/unit',
+    'schemes/Color/tests/unit',
+    'schemes/Shape/tests/unit',
+    'schemes/Typography/tests/unit',
+    'ShadowElevations/tests/unit',
+    'ShadowLayer/tests/unit',
+    'Slider/tests/unit',
+    'Snackbar/tests/unit',
+    'Tabs/tests/unit',
+    'TextFields/tests/unit',
+    'Themes/tests/unit',
+    'Typography/tests/unit',
+  ]
+  pod 'MaterialComponentsAlpha', :path => '../', :testspecs => [
+    'ActionSheet/tests/unit',
+    'NavigationDrawer/tests/unit',
+  ]
   pod 'CatalogByConvention', "~> 2.5"
   pod 'MaterialCatalog', :path => 'MaterialCatalog/'
 
@@ -53,11 +89,12 @@
   # Inject our specific warning flags into the .xcconfig files.
   mdc_xcconfigs = [
     "#{pod_dir}/Target Support Files/MaterialComponents/MaterialComponents.xcconfig",
-    "#{pod_dir}/Target Support Files//MaterialComponentsExamples/MaterialComponentsExamples.xcconfig",
+    "#{pod_dir}/Target Support Files/MaterialComponents/MaterialComponents.unit.xcconfig",
+    "#{pod_dir}/Target Support Files/MaterialComponentsAlpha/MaterialComponentsAlpha.xcconfig",
+    "#{pod_dir}/Target Support Files/MaterialComponentsAlpha/MaterialComponentsAlpha.unit.xcconfig",
+    "#{pod_dir}/Target Support Files/MaterialComponentsExamples/MaterialComponentsExamples.xcconfig",
     "#{pod_dir}/Target Support Files/Pods-MDCCatalog/Pods-MDCCatalog.debug.xcconfig",
     "#{pod_dir}/Target Support Files/Pods-MDCCatalog/Pods-MDCCatalog.release.xcconfig",
-    "#{pod_dir}/Target Support Files/Pods-MDCUnitTests/Pods-MDCUnitTests.debug.xcconfig",
-    "#{pod_dir}/Target Support Files/Pods-MDCUnitTests/Pods-MDCUnitTests.release.xcconfig",
   ]
 
   # Note the path is relative to the xcconfig file being modified.
diff --git a/components/ActionSheet/BUILD b/components/ActionSheet/BUILD
index cc0202e..7d4f17a 100644
--- a/components/ActionSheet/BUILD
+++ b/components/ActionSheet/BUILD
@@ -36,6 +36,7 @@
     srcs = native.glob(["src/TypographyThemer/*.m"]),
     hdrs = native.glob(["src/TypographyThemer/*.h"]),
     includes = ["src/TypographyThemer"],
+    sdk_frameworks = ["UIKit"],
     deps = [
         ":ActionSheet",
         "//components/schemes/Typography",
@@ -44,6 +45,27 @@
 )
 
 mdc_objc_library(
+    name = "ColorThemer",
+    srcs = native.glob(["src/ColorThemer/*.m"]),
+    hdrs = native.glob(["src/ColorThemer/*.h"]),
+    includes = ["src/ColorThemer"],
+    sdk_frameworks = ["UIKit"],
+    deps = [
+        ":ActionSheet",
+        "//components/schemes/Color",
+    ],
+    visibility = ["//visibility:public"],
+)
+
+mdc_objc_library(
+    name = "privateHeaders",
+    testonly = 1,
+    hdrs = native.glob(["src/private/*.h"]),
+    visibility = ["//visibility:private"],
+    deps = [":ActionSheet"],
+)
+
+mdc_objc_library(
     name = "private",
     hdrs = native.glob(["src/private/*.h"]),
     includes = ["src/private"],
@@ -55,6 +77,7 @@
     srcs = glob(["tests/unit/*.swift"]),
     deps = [
         ":ActionSheet",
+        ":ColorThemer",
         ":private",
     ],
     visibility = ["//visibility:private"],
@@ -64,14 +87,20 @@
     name = "unit_test_sources",
     testonly = 1,
     srcs = native.glob([
-        "test/unit/*.m",
-        "test/unit/*.h",
+        "tests/unit/*.m",
+        "tests/unit/*.h",
     ]),
     sdk_frameworks = [
         "UIKit",
+        "CoreImage",
         "XCTest",
     ],
-    deps = [":ActionSheet"],
+    deps = [
+         ":ActionSheet",
+         ":ColorThemer",
+         ":TypographyThemer",
+         ":privateHeaders"
+    ],
     visibility = ["//visibility:private"],
 )
 
diff --git a/components/ActionSheet/README.md b/components/ActionSheet/README.md
index a36b7c0..f0596b6 100644
--- a/components/ActionSheet/README.md
+++ b/components/ActionSheet/README.md
@@ -37,6 +37,8 @@
   - [Typical use](#typical-use)
 - [MDCActionSheetController vs. UIAlertControllerStyleActionSheet](#mdcactionsheetcontroller-vs.-uialertcontrollerstyleactionsheet)
 - [Extensions](#extensions)
+  - [Color Theming](#color-theming)
+  - [Typography Theming](#typography-theming)
 - [Accessibility](#accessibility)
   - [Set `-isScrimAccessibilityElement`](#set-`-isscrimaccessibilityelement`)
   - [Set `-scrimAccessibilityLabel`](#set-`-scrimaccessibilitylabel`)
@@ -163,6 +165,91 @@
 
 ## Extensions
 
+<!-- Extracted from docs/color-theming.md -->
+
+### Color Theming
+
+You can theme an Action Sheet with your app's color scheme using the ColorThemer extension.
+
+You must first add the Color Themer extension to your project:
+
+```bash
+pod `MaterialComponentsAlpha/ActionSheet+ColorThemer`
+```
+
+<!--<div class="material-code-render" markdown="1">-->
+#### Swift
+```swift
+// Step 1: Import the ColorThemer extension
+import MaterialComponentsAlpha.MaterialActionSheet_ColorThemer
+
+// Step 2: Create or get a color scheme
+let colorScheme = MDCSemanticColorScheme()
+
+// Step 3: Apply the color scheme to your component
+let actionSheet = MDCActionSheetController()
+MDCActionSheetColorThemer.applySemanticColorScheme(colorScheme, to: actionSheet)
+```
+
+#### Objective-C
+
+```objc
+// Step 1: Import the ColorThemer extension
+#import "MaterialActionSheet+ColorThemer.h"
+
+// Step 2: Create or get a color scheme
+id<MDCColorScheming> colorScheme = [[MDCSematnicColorScheme alloc] init];
+
+// Step 3: Apply the color scheme to your component
+MDCActionSheetController *actionSheet = [[MDCActionSheetController alloc] init];
+[MDCActionSheetColorThemer applySemanticColorScheme:self.colorScheme
+                            toActionSheetController:actionSheet];
+```
+<!--</div>-->
+
+<!-- Extracted from docs/typography-theming.md -->
+
+### Typography Theming
+
+You can theme an Action Sheet with your app's typography scheme using the TypographyThemer extension.
+
+You must first add the Typography Themer extension to your project:
+
+```bash
+pod `MaterialComponentsAlpha/ActionSheet+TypographyThemer`
+```
+
+<!--<div class="material-code-render" markdown="1">-->
+#### Swift
+```swift
+// Step 1: Import the ColorThemer extension
+import MaterialComponentsAlpha.MaterialActionSheet_TypographyThemer
+
+// Step 2: Create or get a color scheme
+let typographyScheme = MDCTypographyScheme()
+
+// Step 3: Apply the color scheme to your component
+let actionSheet = MDCActionSheetController()
+MDCActionSheetTypographyThemer.applyTypographyScheme(typographyScheme, to: actionSheet)
+```
+
+#### Objective-C
+
+```objc
+// Step 1: Import the ColorThemer extension
+#import "MaterialActionSheet+TypographyThemer.h"
+
+// Step 2: Create or get a color scheme
+id<MDCTypographyScheming> typographyScheme = [[MDCTypographyScheme alloc] init];
+
+// Step 3: Apply the color scheme to your component
+MDCActionSheetController *actionSheet = [[MDCActionSheetController alloc] init];
+[MDCActionSheetTypographyThemer applyTypographyScheme:self.typographyScheme
+                              toActionSheetController:actionSheet];
+```
+<!--</div>-->
+
+
 <!-- Extracted from docs/accessibility.md -->
 
 ## Accessibility
diff --git a/components/ActionSheet/docs/README.md b/components/ActionSheet/docs/README.md
index 2ab0e8f..acecd7f 100644
--- a/components/ActionSheet/docs/README.md
+++ b/components/ActionSheet/docs/README.md
@@ -55,4 +55,7 @@
 
 ## Extensions
 
+- [Color Theming](color-theming.md)
+- [Typography Theming](typography-theming.md)
+
 - [Accessibility](accessibility.md)
diff --git a/components/ActionSheet/docs/color-theming.md b/components/ActionSheet/docs/color-theming.md
new file mode 100644
index 0000000..f5c44be
--- /dev/null
+++ b/components/ActionSheet/docs/color-theming.md
@@ -0,0 +1,39 @@
+### Color Theming
+
+You can theme an Action Sheet with your app's color scheme using the ColorThemer extension.
+
+You must first add the Color Themer extension to your project:
+
+```bash
+pod `MaterialComponentsAlpha/ActionSheet+ColorThemer`
+```
+
+<!--<div class="material-code-render" markdown="1">-->
+#### Swift
+```swift
+// Step 1: Import the ColorThemer extension
+import MaterialComponentsAlpha.MaterialActionSheet_ColorThemer
+
+// Step 2: Create or get a color scheme
+let colorScheme = MDCSemanticColorScheme()
+
+// Step 3: Apply the color scheme to your component
+let actionSheet = MDCActionSheetController()
+MDCActionSheetColorThemer.applySemanticColorScheme(colorScheme, to: actionSheet)
+```
+
+#### Objective-C
+
+```objc
+// Step 1: Import the ColorThemer extension
+#import "MaterialActionSheet+ColorThemer.h"
+
+// Step 2: Create or get a color scheme
+id<MDCColorScheming> colorScheme = [[MDCSematnicColorScheme alloc] init];
+
+// Step 3: Apply the color scheme to your component
+MDCActionSheetController *actionSheet = [[MDCActionSheetController alloc] init];
+[MDCActionSheetColorThemer applySemanticColorScheme:self.colorScheme
+                            toActionSheetController:actionSheet];
+```
+<!--</div>-->
diff --git a/components/ActionSheet/docs/typography-theming.md b/components/ActionSheet/docs/typography-theming.md
new file mode 100644
index 0000000..91f4049
--- /dev/null
+++ b/components/ActionSheet/docs/typography-theming.md
@@ -0,0 +1,39 @@
+### Typography Theming
+
+You can theme an Action Sheet with your app's typography scheme using the TypographyThemer extension.
+
+You must first add the Typography Themer extension to your project:
+
+```bash
+pod `MaterialComponentsAlpha/ActionSheet+TypographyThemer`
+```
+
+<!--<div class="material-code-render" markdown="1">-->
+#### Swift
+```swift
+// Step 1: Import the ColorThemer extension
+import MaterialComponentsAlpha.MaterialActionSheet_TypographyThemer
+
+// Step 2: Create or get a color scheme
+let typographyScheme = MDCTypographyScheme()
+
+// Step 3: Apply the color scheme to your component
+let actionSheet = MDCActionSheetController()
+MDCActionSheetTypographyThemer.applyTypographyScheme(typographyScheme, to: actionSheet)
+```
+
+#### Objective-C
+
+```objc
+// Step 1: Import the ColorThemer extension
+#import "MaterialActionSheet+TypographyThemer.h"
+
+// Step 2: Create or get a color scheme
+id<MDCTypographyScheming> typographyScheme = [[MDCTypographyScheme alloc] init];
+
+// Step 3: Apply the color scheme to your component
+MDCActionSheetController *actionSheet = [[MDCActionSheetController alloc] init];
+[MDCActionSheetTypographyThemer applyTypographyScheme:self.typographyScheme
+                              toActionSheetController:actionSheet];
+```
+<!--</div>-->
diff --git a/components/ActionSheet/examples/ActionSheetSwiftExample.swift b/components/ActionSheet/examples/ActionSheetSwiftExample.swift
index d51c484..f1dccdc 100644
--- a/components/ActionSheet/examples/ActionSheetSwiftExample.swift
+++ b/components/ActionSheet/examples/ActionSheetSwiftExample.swift
@@ -14,6 +14,7 @@
 
 import UIKit
 import MaterialComponentsAlpha.MaterialActionSheet
+import MaterialComponentsAlpha.MaterialActionSheet_ColorThemer
 import MaterialComponentsAlpha.MaterialActionSheet_TypographyThemer
 import MaterialComponents.MaterialColorScheme
 import MaterialComponents.MaterialTypographyScheme
@@ -87,6 +88,7 @@
     case .thirtyOptions:
       actionSheet = ActionSheetSwiftExample.thirtyOptions()
     }
+    MDCActionSheetColorThemer.applySemanticColorScheme(colorScheme, to: actionSheet)
     MDCActionSheetTypographyThemer.applyTypographyScheme(typographyScheme, to: actionSheet)
     present(actionSheet, animated: true, completion: nil)
   }
diff --git a/components/ActionSheet/examples/ActionSheetTypicalUse.m b/components/ActionSheet/examples/ActionSheetTypicalUse.m
index ffba209..108551b 100644
--- a/components/ActionSheet/examples/ActionSheetTypicalUse.m
+++ b/components/ActionSheet/examples/ActionSheetTypicalUse.m
@@ -14,8 +14,10 @@
 
 #import "ActionSheetTypicalUse.h"
 
-#import "MaterialButtons.h"
+#import "MaterialActionSheet+ColorThemer.h"
+#import "MaterialActionSheet+TypographyThemer.h"
 #import "MaterialButtons+ButtonThemer.h"
+#import "MaterialButtons.h"
 
 @interface ActionSheetTypicalUse ()
 
@@ -82,6 +84,10 @@
   [actionSheet addAction:homeAction];
   [actionSheet addAction:favoriteAction];
   [actionSheet addAction:emailAction];
+  [MDCActionSheetColorThemer applySemanticColorScheme:self.colorScheme
+                              toActionSheetController:actionSheet];
+  [MDCActionSheetTypographyThemer applyTypographyScheme:self.typographyScheme
+                                toActionSheetController:actionSheet];
   [self presentViewController:actionSheet animated:YES completion:nil];
 }
 
diff --git a/components/ActionSheet/src/ColorThemer/MDCActionSheetColorThemer.h b/components/ActionSheet/src/ColorThemer/MDCActionSheetColorThemer.h
new file mode 100644
index 0000000..b988c23
--- /dev/null
+++ b/components/ActionSheet/src/ColorThemer/MDCActionSheetColorThemer.h
@@ -0,0 +1,34 @@
+// Copyright 2018-present the Material Components for iOS authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#import "MaterialActionSheet.h"
+#import "MaterialColorScheme.h"
+
+#import <Foundation/Foundation.h>
+
+/**
+ The Material Design color system's themer for instances of MDCActionSheetController.
+ */
+@interface MDCActionSheetColorThemer : NSObject
+
+/**
+ Applies a color scheme's properties to an MDCActionSheetController
+
+ @param colorScheme The color scheme to apply to the component instance.
+ @param actionSheetController A component instance to which the olor scheme should be applied.
+ */
++ (void)applySemanticColorScheme:(nonnull id<MDCColorScheming>)colorScheme
+         toActionSheetController:(nonnull MDCActionSheetController *)actionSheetController;
+
+@end
diff --git a/components/ActionSheet/src/ColorThemer/MDCActionSheetColorThemer.m b/components/ActionSheet/src/ColorThemer/MDCActionSheetColorThemer.m
new file mode 100644
index 0000000..7cfe6e1
--- /dev/null
+++ b/components/ActionSheet/src/ColorThemer/MDCActionSheetColorThemer.m
@@ -0,0 +1,44 @@
+// Copyright 2018-present the Material Components for iOS authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#import "MDCActionSheetColorThemer.h"
+
+static const CGFloat kHighAlpha = 0.87f;
+static const CGFloat kMediumAlpha = 0.6f;
+static const CGFloat kInkAlpha = 16.f;
+
+@implementation MDCActionSheetColorThemer
+
++ (void)applySemanticColorScheme:(id<MDCColorScheming>)colorScheme
+         toActionSheetController:(MDCActionSheetController *)actionSheetController {
+  actionSheetController.backgroundColor = colorScheme.surfaceColor;
+  if (actionSheetController.message && ![actionSheetController.message isEqualToString:@""]) {
+    // If there is a message then this can be high opacity and won't clash with actions.
+    actionSheetController.titleTextColor =
+        [colorScheme.onSurfaceColor colorWithAlphaComponent:kHighAlpha];
+  } else {
+    actionSheetController.titleTextColor =
+        [colorScheme.onSurfaceColor colorWithAlphaComponent:kMediumAlpha];
+  }
+  actionSheetController.messageTextColor =
+      [colorScheme.onSurfaceColor colorWithAlphaComponent:kMediumAlpha];
+  actionSheetController.imageRenderingMode = UIImageRenderingModeAlwaysTemplate;
+  actionSheetController.actionTintColor =
+      [colorScheme.onSurfaceColor colorWithAlphaComponent:kMediumAlpha];
+  actionSheetController.actionTextColor =
+      [colorScheme.onSurfaceColor colorWithAlphaComponent:kHighAlpha];
+  actionSheetController.inkColor = [colorScheme.onSurfaceColor colorWithAlphaComponent:kInkAlpha];
+}
+
+@end
diff --git a/components/ActionSheet/src/ColorThemer/MaterialActionSheet+ColorThemer.h b/components/ActionSheet/src/ColorThemer/MaterialActionSheet+ColorThemer.h
new file mode 100644
index 0000000..509da44
--- /dev/null
+++ b/components/ActionSheet/src/ColorThemer/MaterialActionSheet+ColorThemer.h
@@ -0,0 +1,15 @@
+// Copyright 2018-present the Material Components for iOS authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#import "MDCActionSheetColorThemer.h"
diff --git a/components/ActionSheet/src/MDCActionSheetController.h b/components/ActionSheet/src/MDCActionSheetController.h
index 36a701c..19591e3 100644
--- a/components/ActionSheet/src/MDCActionSheetController.h
+++ b/components/ActionSheet/src/MDCActionSheetController.h
@@ -143,6 +143,42 @@
  */
 @property(nonatomic, nonnull, strong) UIColor *backgroundColor;
 
+/**
+ The color applied to the title of the action sheet controller.
+
+ @note If only using a title and the actions have no icons make sure they are different colors so
+ there is a distinction between the title and actions.
+ */
+@property(nonatomic, strong, nullable) UIColor *titleTextColor;
+
+/**
+ The color applied to the message of the action sheet controller.
+
+ @note To make for a better user experience we recommend using a different color for the message and
+ actions if there are no icons so there is a distinction between the message and actions.
+ */
+@property(nonatomic, strong, nullable) UIColor *messageTextColor;
+
+/**
+ The color for the text for all action items within an action sheet.
+ */
+@property(nonatomic, strong, nullable) UIColor *actionTextColor;
+
+/**
+ The tint color for the action items within an action sheet.
+ */
+@property(nonatomic, strong, nullable) UIColor *actionTintColor;
+
+/**
+ The ink color for the action items within an action sheet.
+ */
+@property(nonatomic, strong, nullable) UIColor *inkColor;
+
+/**
+ The image rendering mode for all actions within an action sheet.
+ */
+@property(nonatomic) UIImageRenderingMode imageRenderingMode;
+
 @property(nonatomic, strong, readonly, nonnull)
     MDCBottomSheetTransitionController *transitionController;
 
diff --git a/components/ActionSheet/src/MDCActionSheetController.m b/components/ActionSheet/src/MDCActionSheetController.m
index a21223f..df5a5d5 100644
--- a/components/ActionSheet/src/MDCActionSheetController.m
+++ b/components/ActionSheet/src/MDCActionSheetController.m
@@ -14,11 +14,14 @@
 
 #import "MDCActionSheetController.h"
 
-#import "private/MDCActionSheetItemTableViewCell.h"
-#import "private/MDCActionSheetHeaderView.h"
+#import "MaterialMath.h"
 #import "MaterialTypography.h"
+#import "private/MDCActionSheetHeaderView.h"
+#import "private/MDCActionSheetItemTableViewCell.h"
 
-static NSString *const ReuseIdentifier = @"BaseCell";
+static NSString *const kReuseIdentifier = @"BaseCell";
+static const CGFloat kActionImageAlpha = 0.6f;
+static const CGFloat kActionTextAlpha = 0.87f;
 
 @interface MDCActionSheetAction ()
 
@@ -104,7 +107,7 @@
     _tableView.rowHeight = UITableViewAutomaticDimension;
     _tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
     [_tableView registerClass:[MDCActionSheetItemTableViewCell class]
-       forCellReuseIdentifier:ReuseIdentifier];
+        forCellReuseIdentifier:kReuseIdentifier];
 
     _header = [[MDCActionSheetHeaderView alloc] initWithFrame:CGRectZero];
     _header.title = [title copy];
@@ -112,6 +115,9 @@
     _backgroundColor = UIColor.whiteColor;
     _header.backgroundColor = _backgroundColor;
     _tableView.backgroundColor = _backgroundColor;
+    _actionTextColor = [UIColor.blackColor colorWithAlphaComponent:kActionTextAlpha];
+    _actionTintColor = [UIColor.blackColor colorWithAlphaComponent:kActionImageAlpha];
+    _imageRenderingMode = UIImageRenderingModeAlwaysTemplate;
   }
 
   return self;
@@ -142,6 +148,11 @@
 - (void)viewWillLayoutSubviews {
   [super viewWillLayoutSubviews];
 
+  if (self.tableView.contentSize.height > (CGRectGetHeight(self.view.bounds) / 2)) {
+    self.mdc_bottomSheetPresentationController.preferredSheetHeight = [self openingSheetHeight];
+  } else {
+    self.mdc_bottomSheetPresentationController.preferredSheetHeight = 0;
+  }
   CGSize size = [self.header sizeThatFits:CGRectStandardize(self.view.bounds).size];
   self.header.frame = CGRectMake(0, 0, self.view.bounds.size.width, size.height);
   UIEdgeInsets insets = UIEdgeInsetsMake(self.header.frame.size.height, 0, 0, 0);
@@ -154,6 +165,28 @@
   self.tableView.contentOffset = CGPointMake(0, -size.height);
 }
 
+- (CGFloat)openingSheetHeight {
+  // If there are too many options to fit on half of the screen then show as many options as
+  // possible minus half a cell, to allow for bleeding and signal to the user that the sheet is
+  // scrollable content.
+  CGFloat maxHeight = CGRectGetHeight(self.view.bounds) / 2;
+  CGFloat headerHeight = [self.header sizeThatFits:CGRectStandardize(self.view.bounds).size].height;
+  CGFloat cellHeight = self.tableView.contentSize.height / (CGFloat)_actions.count;
+  CGFloat maxTableHeight = maxHeight - headerHeight;
+  NSInteger amountOfCellsToShow = (NSInteger)(maxTableHeight / cellHeight);
+  // There is already a partially shown cell that is showing and more than half is visable
+  if (fmod(maxTableHeight, cellHeight) > (cellHeight * 0.5f)) {
+    amountOfCellsToShow += 1;
+  }
+  CGFloat preferredHeight = (((CGFloat)amountOfCellsToShow - 0.5f) * cellHeight) + headerHeight;
+  // When updating the preferredSheetHeight the presentation controller takes into account the
+  // safe area so we have to remove that.
+  if (@available(iOS 11.0, *)) {
+    preferredHeight = preferredHeight - self.view.safeAreaInsets.bottom;
+  }
+  return MDCCeil(preferredHeight);
+}
+
 - (void)viewWillAppear:(BOOL)animated {
   [super viewWillAppear:animated];
 
@@ -255,13 +288,17 @@
 - (UITableViewCell *)tableView:(UITableView *)tableView
          cellForRowAtIndexPath:(NSIndexPath *)indexPath {
   MDCActionSheetItemTableViewCell *cell =
-      [tableView dequeueReusableCellWithIdentifier:ReuseIdentifier forIndexPath:indexPath];
+      [tableView dequeueReusableCellWithIdentifier:kReuseIdentifier forIndexPath:indexPath];
   MDCActionSheetAction *action = _actions[indexPath.row];
   cell.action = action;
   cell.mdc_adjustsFontForContentSizeCategory = self.mdc_adjustsFontForContentSizeCategory;
   cell.backgroundColor = self.backgroundColor;
   cell.actionFont = self.actionFont;
   cell.accessibilityIdentifier = action.accessibilityIdentifier;
+  cell.inkColor = self.inkColor;
+  cell.tintColor = self.actionTintColor;
+  cell.imageRenderingMode = self.imageRenderingMode;
+  cell.actionTextColor = self.actionTextColor;
   return cell;
 }
 
@@ -306,6 +343,22 @@
   self.header.backgroundColor = backgroundColor;
 }
 
+- (void)setTitleTextColor:(UIColor *)titleTextColor {
+  self.header.titleTextColor = titleTextColor;
+}
+
+- (UIColor *)titleTextColor {
+  return self.header.titleTextColor;
+}
+
+- (void)setMessageTextColor:(UIColor *)messageTextColor {
+  self.header.messageTextColor = messageTextColor;
+}
+
+- (UIColor *)messageTextColor {
+  return self.header.messageTextColor;
+}
+
 #pragma mark - Dynamic Type
 
 - (void)mdc_setAdjustsFontForContentSizeCategory:(BOOL)adjusts {
@@ -342,4 +395,31 @@
   [self.view setNeedsLayout];
 }
 
+#pragma mark - Table customization
+
+- (void)setActionFont:(UIFont *)actionFont {
+  _actionFont = actionFont;
+  [self.tableView reloadData];
+}
+
+- (void)setActionTextColor:(UIColor *)actionTextColor {
+  _actionTextColor = actionTextColor;
+  [self.tableView reloadData];
+}
+
+- (void)setActionTintColor:(UIColor *)actionTintColor {
+  _actionTintColor = actionTintColor;
+  [self.tableView reloadData];
+}
+
+- (void)setImageRenderingMode:(UIImageRenderingMode)imageRenderingMode {
+  _imageRenderingMode = imageRenderingMode;
+  [self.tableView reloadData];
+}
+
+- (void)setInkColor:(UIColor *)inkColor {
+  _inkColor = inkColor;
+  [self.tableView reloadData];
+}
+
 @end
diff --git a/components/ActionSheet/src/private/MDCActionSheetHeaderView.h b/components/ActionSheet/src/private/MDCActionSheetHeaderView.h
index ead083b..83c90d0 100644
--- a/components/ActionSheet/src/private/MDCActionSheetHeaderView.h
+++ b/components/ActionSheet/src/private/MDCActionSheetHeaderView.h
@@ -32,4 +32,8 @@
 
 @property (nonatomic, strong, nonnull) UIFont *messageFont;
 
+@property(nonatomic, strong, nullable) UIColor *titleTextColor;
+
+@property(nonatomic, strong, nullable) UIColor *messageTextColor;
+
 @end
diff --git a/components/ActionSheet/src/private/MDCActionSheetHeaderView.m b/components/ActionSheet/src/private/MDCActionSheetHeaderView.m
index 220fd34..afa88fa 100644
--- a/components/ActionSheet/src/private/MDCActionSheetHeaderView.m
+++ b/components/ActionSheet/src/private/MDCActionSheetHeaderView.m
@@ -17,14 +17,14 @@
 #import "MaterialMath.h"
 #import "MaterialTypography.h"
 
-static const CGFloat TitleLabelAlpha = 0.87f;
-static const CGFloat MessageLabelAlpha = 0.6f;
-static const CGFloat MessageOnlyPadding = 23.f;
-static const CGFloat LeadingPadding = 16.f;
-static const CGFloat TopStandardPadding = 16.f;
-static const CGFloat TrailingPadding = 16.f;
-static const CGFloat TitleOnlyPadding = 18.f;
-static const CGFloat MiddlePadding = 8.f;
+static const CGFloat kTitleLabelAlpha = 0.87f;
+static const CGFloat kMessageLabelAlpha = 0.6f;
+static const CGFloat kMessageOnlyPadding = 23.f;
+static const CGFloat kLeadingPadding = 16.f;
+static const CGFloat kTopStandardPadding = 16.f;
+static const CGFloat kTrailingPadding = 16.f;
+static const CGFloat kTitleOnlyPadding = 18.f;
+static const CGFloat kMiddlePadding = 8.f;
 
 @interface MDCActionSheetHeaderView ()
 @property(nonatomic, strong) UILabel *titleLabel;
@@ -49,7 +49,7 @@
     _messageLabel.font = [UIFont mdc_standardFontForMaterialTextStyle:MDCFontTextStyleBody1];
     _messageLabel.numberOfLines = 2;
     _messageLabel.lineBreakMode = NSLineBreakByWordWrapping;
-    _messageLabel.textColor = [UIColor.blackColor colorWithAlphaComponent:MessageLabelAlpha];
+    _messageLabel.textColor = [UIColor.blackColor colorWithAlphaComponent:kMessageLabelAlpha];
   }
   return self;
 }
@@ -65,32 +65,32 @@
   size.width = CGRectGetWidth(self.bounds);
   CGRect labelFrame = [self frameWithSafeAreaInsets:self.bounds];
   labelFrame = CGRectStandardize(labelFrame);
-  labelFrame.size.width = labelFrame.size.width - LeadingPadding - TrailingPadding;
+  labelFrame.size.width = labelFrame.size.width - kLeadingPadding - kTrailingPadding;
   CGSize titleSize = [self.titleLabel sizeThatFits:labelFrame.size];
   CGSize messageSize = [self.messageLabel sizeThatFits:labelFrame.size];
-  CGRect titleFrame = CGRectMake(LeadingPadding + labelFrame.origin.x, TopStandardPadding,
+  CGRect titleFrame = CGRectMake(kLeadingPadding + labelFrame.origin.x, kTopStandardPadding,
                                  labelFrame.size.width, titleSize.height);
-  CGRect messageFrame = CGRectMake(LeadingPadding + labelFrame.origin.x,
-                                   CGRectGetMaxY(titleFrame) + MiddlePadding,
-                                   labelFrame.size.width, messageSize.height);
+  CGRect messageFrame =
+      CGRectMake(kLeadingPadding + labelFrame.origin.x, CGRectGetMaxY(titleFrame) + kMiddlePadding,
+                 labelFrame.size.width, messageSize.height);
   self.titleLabel.frame = titleFrame;
   self.messageLabel.frame = messageFrame;
 }
 
 - (CGSize)sizeThatFits:(CGSize)size {
-  size.width = size.width - LeadingPadding - TrailingPadding;
+  size.width = size.width - kLeadingPadding - kTrailingPadding;
   CGSize titleSize = [self.titleLabel sizeThatFits:size];
   CGSize messageSize = [self.messageLabel sizeThatFits:size];
   CGFloat contentHeight;
   BOOL messageExist = (self.message) && (![self.message isEqualToString:@""]);
   BOOL titleExist = (self.title) && (![self.title isEqualToString:@""]);
   if (titleExist && messageExist) {
-    contentHeight = titleSize.height + messageSize.height +
-        (TopStandardPadding * 2) + MiddlePadding;
+    contentHeight =
+        titleSize.height + messageSize.height + (kTopStandardPadding * 2) + kMiddlePadding;
   } else if (messageExist) {
-    contentHeight = messageSize.height + (MessageOnlyPadding * 2);
+    contentHeight = messageSize.height + (kMessageOnlyPadding * 2);
   } else if (titleExist) {
-    contentHeight = titleSize.height + (TitleOnlyPadding * 2);
+    contentHeight = titleSize.height + (kTitleOnlyPadding * 2);
   } else {
     contentHeight = 0;
   }
@@ -122,13 +122,7 @@
 
 - (void)setMessage:(NSString *)message {
   self.messageLabel.text = message;
-  // If message is empty or nil then the title label's alpha value should be lighter, if there is both
-  // then the title label's alpha should be darker.
-  if (self.message && ![self.message isEqualToString:@""]) {
-    _titleLabel.textColor = [UIColor.blackColor colorWithAlphaComponent:TitleLabelAlpha];
-  } else {
-    _titleLabel.textColor = [UIColor.blackColor colorWithAlphaComponent:MessageLabelAlpha];
-  }
+  [self updateLabelColors];
   [self setNeedsLayout];
 }
 
@@ -201,4 +195,30 @@
   [self updateFonts];
 }
 
+- (UIColor *)defaultTitleTextColor {
+  // If message is empty or nil then the title label's alpha value should be lighter, if there is
+  // both then the title label's alpha should be darker.
+  if (self.message && ![self.message isEqualToString:@""]) {
+    return [UIColor.blackColor colorWithAlphaComponent:kTitleLabelAlpha];
+  } else {
+    return [UIColor.blackColor colorWithAlphaComponent:kMessageLabelAlpha];
+  }
+}
+
+- (void)updateLabelColors {
+  self.titleLabel.textColor = self.titleTextColor ?: [self defaultTitleTextColor];
+  self.messageLabel.textColor =
+      self.messageTextColor ?: [UIColor.blackColor colorWithAlphaComponent:kMessageLabelAlpha];
+}
+
+- (void)setTitleTextColor:(UIColor *)titleTextColor {
+  _titleTextColor = titleTextColor;
+  [self updateLabelColors];
+}
+
+- (void)setMessageTextColor:(UIColor *)messageTextColor {
+  _messageTextColor = messageTextColor;
+  [self updateLabelColors];
+}
+
 @end
diff --git a/components/ActionSheet/src/private/MDCActionSheetItemTableViewCell.h b/components/ActionSheet/src/private/MDCActionSheetItemTableViewCell.h
index d392778..ca031ad 100644
--- a/components/ActionSheet/src/private/MDCActionSheetItemTableViewCell.h
+++ b/components/ActionSheet/src/private/MDCActionSheetItemTableViewCell.h
@@ -28,4 +28,10 @@
 
 @property(nonatomic, nonnull, strong) UIFont *actionFont;
 
+@property(nonatomic, strong, nullable) UIColor *actionTextColor;
+
+@property(nonatomic, strong, nullable) UIColor *inkColor;
+
+@property(nonatomic) UIImageRenderingMode imageRenderingMode;
+
 @end
diff --git a/components/ActionSheet/src/private/MDCActionSheetItemTableViewCell.m b/components/ActionSheet/src/private/MDCActionSheetItemTableViewCell.m
index 9716fcf..7d9a1b9 100644
--- a/components/ActionSheet/src/private/MDCActionSheetItemTableViewCell.m
+++ b/components/ActionSheet/src/private/MDCActionSheetItemTableViewCell.m
@@ -16,22 +16,24 @@
 
 #import "MaterialTypography.h"
 
-static const CGFloat ImageAlpha = 0.6f;
-static const CGFloat LabelAlpha = 0.87f;
-static const CGFloat ImageLeadingPadding = 16.f;
-static const CGFloat ImageTopPadding = 16.f;
-static const CGFloat ImageHeightAndWidth = 24.f;
-static const CGFloat TitleLeadingPadding = 72.f;
-static const CGFloat TitleTrailingPadding = 16.f;
-static const CGFloat ActionItemTitleVerticalPadding = 18.f;
+static const CGFloat kLabelAlpha = 0.87f;
+static const CGFloat kImageLeadingPadding = 16.f;
+static const CGFloat kImageTopPadding = 16.f;
+static const CGFloat kImageHeightAndWidth = 24.f;
+static const CGFloat kTitleLeadingPadding = 72.f;
+static const CGFloat kTitleTrailingPadding = 16.f;
+static const CGFloat kActionItemTitleVerticalPadding = 18.f;
+
+@interface MDCActionSheetItemTableViewCell ()
+@property(nonatomic, strong) UILabel *actionLabel;
+@property(nonatomic, strong) UIImageView *actionImageView;
+@property(nonatomic, strong) MDCInkTouchController *inkTouchController;
+@end
 
 @implementation MDCActionSheetItemTableViewCell {
   MDCActionSheetAction *_itemAction;
-  UILabel *_textLabel;
-  UIImageView *_imageView;
   NSLayoutConstraint *_titleLeadingConstraint;
   NSLayoutConstraint *_titleWidthConstraint;
-  MDCInkTouchController *_inkTouchController;
 }
 
 @synthesize mdc_adjustsFontForContentSizeCategory = _mdc_adjustsFontForContentSizeCategory;
@@ -49,35 +51,37 @@
   self.translatesAutoresizingMaskIntoConstraints = NO;
   self.selectionStyle = UITableViewCellSelectionStyleNone;
   self.accessibilityTraits = UIAccessibilityTraitButton;
-  _textLabel = [[UILabel alloc] init];
-  [self.contentView addSubview:_textLabel];
-  _textLabel.numberOfLines = 0;
-  _textLabel.translatesAutoresizingMaskIntoConstraints = NO;
-  [_textLabel sizeToFit];
-  _textLabel.font = [UIFont mdc_preferredFontForMaterialTextStyle:MDCFontTextStyleSubheadline];
-  _textLabel.lineBreakMode = NSLineBreakByTruncatingMiddle;
-  _textLabel.textColor = [UIColor.blackColor colorWithAlphaComponent:LabelAlpha];
+  _actionLabel = [[UILabel alloc] init];
+  [self.contentView addSubview:_actionLabel];
+  _actionLabel.numberOfLines = 0;
+  _actionLabel.translatesAutoresizingMaskIntoConstraints = NO;
+  [_actionLabel sizeToFit];
+  _actionLabel.font = [UIFont mdc_preferredFontForMaterialTextStyle:MDCFontTextStyleSubheadline];
+  _actionLabel.lineBreakMode = NSLineBreakByTruncatingMiddle;
+  _actionLabel.textColor = [UIColor.blackColor colorWithAlphaComponent:kLabelAlpha];
   CGFloat leadingConstant;
   if (_itemAction.image) {
-    leadingConstant = TitleLeadingPadding;
+    leadingConstant = kTitleLeadingPadding;
   } else {
-    leadingConstant = ImageLeadingPadding;
+    leadingConstant = kImageLeadingPadding;
   }
-  [NSLayoutConstraint constraintWithItem:_textLabel
+  [NSLayoutConstraint constraintWithItem:_actionLabel
                                attribute:NSLayoutAttributeTop
                                relatedBy:NSLayoutRelationEqual
                                   toItem:self.contentView
                                attribute:NSLayoutAttributeTop
                               multiplier:1
-                                constant:ActionItemTitleVerticalPadding].active = YES;
-  [NSLayoutConstraint constraintWithItem:_textLabel
+                                constant:kActionItemTitleVerticalPadding]
+      .active = YES;
+  [NSLayoutConstraint constraintWithItem:_actionLabel
                                attribute:NSLayoutAttributeBottom
                                relatedBy:NSLayoutRelationEqual
                                   toItem:self.contentView
                                attribute:NSLayoutAttributeBottom
                               multiplier:1
-                                constant:-ActionItemTitleVerticalPadding].active = YES;
-  _titleLeadingConstraint = [NSLayoutConstraint constraintWithItem:_textLabel
+                                constant:-kActionItemTitleVerticalPadding]
+      .active = YES;
+  _titleLeadingConstraint = [NSLayoutConstraint constraintWithItem:_actionLabel
                                                          attribute:NSLayoutAttributeLeading
                                                          relatedBy:NSLayoutRelationEqual
                                                             toItem:self.contentView
@@ -85,8 +89,8 @@
                                                         multiplier:1
                                                           constant:leadingConstant];
   _titleLeadingConstraint.active = YES;
-  CGFloat width = CGRectGetWidth(self.contentView.frame) - leadingConstant - TitleTrailingPadding;
-  _titleWidthConstraint = [NSLayoutConstraint constraintWithItem:_textLabel
+  CGFloat width = CGRectGetWidth(self.contentView.frame) - leadingConstant - kTitleTrailingPadding;
+  _titleWidthConstraint = [NSLayoutConstraint constraintWithItem:_actionLabel
                                                        attribute:NSLayoutAttributeWidth
                                                        relatedBy:NSLayoutRelationEqual
                                                           toItem:nil
@@ -99,61 +103,64 @@
     [_inkTouchController addInkView];
   }
 
-  _imageView = [[UIImageView alloc] init];
-  [self.contentView addSubview:_imageView];
-  _imageView.translatesAutoresizingMaskIntoConstraints = NO;
-  _imageView.alpha = ImageAlpha;
-  [NSLayoutConstraint constraintWithItem:_imageView
+  _actionImageView = [[UIImageView alloc] init];
+  [self.contentView addSubview:_actionImageView];
+  _actionImageView.translatesAutoresizingMaskIntoConstraints = NO;
+  [NSLayoutConstraint constraintWithItem:_actionImageView
                                attribute:NSLayoutAttributeTop
                                relatedBy:NSLayoutRelationEqual
                                   toItem:self.contentView
                                attribute:NSLayoutAttributeTop
                               multiplier:1
-                                constant:ImageTopPadding].active = YES;
-  [NSLayoutConstraint constraintWithItem:_imageView
+                                constant:kImageTopPadding]
+      .active = YES;
+  [NSLayoutConstraint constraintWithItem:_actionImageView
                                attribute:NSLayoutAttributeLeading
                                relatedBy:NSLayoutRelationEqual
                                   toItem:self.contentView
                                attribute:NSLayoutAttributeLeading
                               multiplier:1
-                                constant:ImageLeadingPadding].active = YES;
-  [NSLayoutConstraint constraintWithItem:_imageView
+                                constant:kImageLeadingPadding]
+      .active = YES;
+  [NSLayoutConstraint constraintWithItem:_actionImageView
                                attribute:NSLayoutAttributeWidth
                                relatedBy:NSLayoutRelationEqual
                                   toItem:nil
                                attribute:NSLayoutAttributeNotAnAttribute
                               multiplier:1
-                                constant:ImageHeightAndWidth].active = YES;
-  [NSLayoutConstraint constraintWithItem:_imageView
+                                constant:kImageHeightAndWidth]
+      .active = YES;
+  [NSLayoutConstraint constraintWithItem:_actionImageView
                                attribute:NSLayoutAttributeHeight
                                relatedBy:NSLayoutRelationEqual
                                   toItem:nil
                                attribute:NSLayoutAttributeNotAnAttribute
                               multiplier:1
-                                constant:ImageHeightAndWidth].active = YES;
+                                constant:kImageHeightAndWidth]
+      .active = YES;
 }
 
 - (void)layoutSubviews {
   [super layoutSubviews];
 
-  _textLabel.text = _itemAction.title;
+  self.actionLabel.text = _itemAction.title;
   CGFloat leadingConstant;
   if (_itemAction.image) {
-    leadingConstant = TitleLeadingPadding;
+    leadingConstant = kTitleLeadingPadding;
   } else {
-    leadingConstant = ImageLeadingPadding;
+    leadingConstant = kImageLeadingPadding;
   }
   _titleLeadingConstraint.constant = leadingConstant;
-  CGFloat width = CGRectGetWidth(self.contentView.frame) - leadingConstant - TitleTrailingPadding;
+  CGFloat width = CGRectGetWidth(self.contentView.frame) - leadingConstant - kTitleTrailingPadding;
   _titleWidthConstraint.constant = width;
 
-  _imageView.image = _itemAction.image;
+  self.actionImageView.image = [_itemAction.image imageWithRenderingMode:self.imageRenderingMode];
 }
 
 - (void)setAction:(MDCActionSheetAction *)action {
   _itemAction = [action copy];
-  _textLabel.text = _itemAction.title;
-  _imageView.image = _itemAction.image;
+  self.actionLabel.text = _itemAction.title;
+  self.actionImageView.image = _itemAction.image;
   [self setNeedsLayout];
 }
 
@@ -161,7 +168,7 @@
   return _itemAction;
 }
 
-- (void)setActionsFont:(UIFont *)actionFont {
+- (void)setActionFont:(UIFont *)actionFont {
   _actionFont = actionFont;
   [self updateTitleFont];
 }
@@ -170,11 +177,11 @@
   UIFont *titleFont = _actionFont ?:
       [UIFont mdc_standardFontForMaterialTextStyle:MDCFontTextStyleSubheadline];
   if (self.mdc_adjustsFontForContentSizeCategory) {
-    _textLabel.font =
+    self.actionLabel.font =
         [titleFont mdc_fontSizedForMaterialTextStyle:MDCFontTextStyleSubheadline
                                 scaledForDynamicType:self.mdc_adjustsFontForContentSizeCategory];
   } else {
-    _textLabel.font = titleFont;
+    self.actionLabel.font = titleFont;
   }
   [self setNeedsLayout];
 }
@@ -184,4 +191,22 @@
   [self updateTitleFont];
 }
 
+- (void)setActionTextColor:(UIColor *)actionTextColor {
+  _actionTextColor = actionTextColor;
+  _actionLabel.textColor =
+      actionTextColor ?: [UIColor.blackColor colorWithAlphaComponent:kLabelAlpha];
+}
+
+- (void)setInkColor:(UIColor *)inkColor {
+  _inkColor = inkColor;
+  // If no ink color then reset to the default ink color
+  self.inkTouchController.defaultInkView.inkColor =
+      inkColor ?: [[UIColor alloc] initWithWhite:0 alpha:0.14f];
+}
+
+- (void)setImageRenderingMode:(UIImageRenderingMode)imageRenderingMode {
+  _imageRenderingMode = imageRenderingMode;
+  [self setNeedsLayout];
+}
+
 @end
diff --git a/components/ActionSheet/tests/unit/ActionSheetTest.swift b/components/ActionSheet/tests/unit/ActionSheetTest.swift
index 4ad13ee..0af5af7 100644
--- a/components/ActionSheet/tests/unit/ActionSheetTest.swift
+++ b/components/ActionSheet/tests/unit/ActionSheetTest.swift
@@ -14,6 +14,7 @@
 
 import XCTest
 import MaterialComponentsAlpha.MaterialActionSheet
+import MaterialComponentsAlpha.MaterialActionSheet_ColorThemer
 
 class ActionSheetTest: XCTestCase {
 
@@ -90,17 +91,6 @@
     }
   }
 
-  func testSetBackgroundColor() {
-    // Given
-    let newBackgroundColor: UIColor = .green
-
-    // When
-    actionSheet.backgroundColor = newBackgroundColor
-
-    // Then
-    XCTAssertEqual(actionSheet.backgroundColor, newBackgroundColor)
-  }
-
   func testBackgroundColorMatchesViewBackgroundColor() {
     // Given
     let newBackgroundColor: UIColor = .green
@@ -113,4 +103,19 @@
     XCTAssertEqual(actionSheet.view.backgroundColor, actionSheet.backgroundColor)
     XCTAssertEqual(actionSheet.view.backgroundColor, newBackgroundColor)
   }
+
+  func testApplyThemerToBackgroundColor() {
+    // Given
+    let surfaceColor: UIColor = .blue
+    let colorScheme = MDCSemanticColorScheme()
+    colorScheme.surfaceColor = surfaceColor
+
+    // When
+    MDCActionSheetColorThemer.applySemanticColorScheme(colorScheme, to: actionSheet)
+    let _ = actionSheet.view
+
+    // Then
+    XCTAssertEqual(actionSheet.view.backgroundColor, surfaceColor)
+    XCTAssertEqual(actionSheet.backgroundColor, surfaceColor)
+  }
 }
diff --git a/components/ActionSheet/tests/unit/MDCActionSheetTableCellTest.m b/components/ActionSheet/tests/unit/MDCActionSheetTableCellTest.m
new file mode 100644
index 0000000..7606289
--- /dev/null
+++ b/components/ActionSheet/tests/unit/MDCActionSheetTableCellTest.m
@@ -0,0 +1,149 @@
+// Copyright 2018-present the Material Components for iOS authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#import <XCTest/XCTest.h>
+
+#import "../../src/private/MDCActionSheetItemTableViewCell.h"
+#import "MDCActionSheetTestHelper.h"
+
+@interface MDCActionSheetItemTableViewCell (Testing)
+@property(nonatomic, strong) UILabel *actionLabel;
+@property(nonatomic, strong) UIImageView *actionImageView;
+@property(nonatomic, strong) MDCInkTouchController *inkTouchController;
+@end
+
+@interface MDCActionSheetTableCellTest : XCTestCase
+@property(nonatomic, strong) MDCActionSheetController *actionSheet;
+@end
+
+@implementation MDCActionSheetTableCellTest
+
+- (void)setUp {
+  [super setUp];
+
+  self.actionSheet = [[MDCActionSheetController alloc] init];
+}
+
+- (void)testDefaultRenderingMode {
+  // When
+  NSArray *cells = [MDCActionSheetTestHelper getCellsFromActionSheet:self.actionSheet];
+
+  // Then
+  for (MDCActionSheetItemTableViewCell *cell in cells) {
+    XCTAssertEqual(cell.imageRenderingMode, UIImageRenderingModeAlwaysTemplate);
+  }
+}
+
+- (void)testSetImageRenderingMode {
+  // When
+  UIImageRenderingMode imageMode = UIImageRenderingModeAlwaysOriginal;
+  self.actionSheet.imageRenderingMode = imageMode;
+  NSArray *cells = [MDCActionSheetTestHelper getCellsFromActionSheet:self.actionSheet];
+
+  // Then
+  for (MDCActionSheetItemTableViewCell *cell in cells) {
+    XCTAssertEqual(cell.imageRenderingMode, imageMode);
+  }
+}
+
+- (void)testDefaultCellActionTextColor {
+  // When
+  NSArray *cells = [MDCActionSheetTestHelper getCellsFromActionSheet:self.actionSheet];
+
+  // Then
+  for (MDCActionSheetItemTableViewCell *cell in cells) {
+    XCTAssertEqualObjects(cell.actionLabel.textColor,
+                          [UIColor.blackColor colorWithAlphaComponent:0.87f]);
+  }
+}
+
+- (void)testSetActionTextColor {
+  // When
+  NSArray *colors = [MDCActionSheetTestHelper colorsToTest];
+
+  for (UIColor *color in colors) {
+    self.actionSheet.actionTextColor = color;
+    NSArray *cells = [MDCActionSheetTestHelper getCellsFromActionSheet:self.actionSheet];
+    for (MDCActionSheetItemTableViewCell *cell in cells) {
+      // Then
+      XCTAssertEqualObjects(cell.actionLabel.textColor, color);
+    }
+  }
+}
+
+- (void)testDefaultCellTintColor {
+  // When
+  NSArray *cells = [MDCActionSheetTestHelper getCellsFromActionSheet:self.actionSheet];
+
+  // Then
+  for (MDCActionSheetItemTableViewCell *cell in cells) {
+    XCTAssertEqualObjects(cell.actionImageView.tintColor,
+                          [UIColor.blackColor colorWithAlphaComponent:0.6f]);
+  }
+}
+
+- (void)testSetTintColor {
+  // When
+  NSArray *colors = [MDCActionSheetTestHelper colorsToTest];
+
+  for (UIColor *color in colors) {
+    self.actionSheet.actionTintColor = color;
+    NSArray *cells = [MDCActionSheetTestHelper getCellsFromActionSheet:self.actionSheet];
+    for (MDCActionSheetItemTableViewCell *cell in cells) {
+      // Then
+      XCTAssertEqualObjects(cell.actionImageView.tintColor, color);
+    }
+  }
+}
+
+- (void)testDefaultInkColor {
+  // When
+  NSArray *cells = [MDCActionSheetTestHelper getCellsFromActionSheet:self.actionSheet];
+
+  // Then
+  for (MDCActionSheetItemTableViewCell *cell in cells) {
+    XCTAssertEqualObjects(cell.inkTouchController.defaultInkView.inkColor,
+                          [[UIColor alloc] initWithWhite:0 alpha:0.14f]);
+  }
+}
+
+- (void)testSetInkColor {
+  // When
+  NSArray *colors = [MDCActionSheetTestHelper colorsToTest];
+
+  for (UIColor *color in colors) {
+    self.actionSheet.inkColor = color;
+    NSArray *cells = [MDCActionSheetTestHelper getCellsFromActionSheet:self.actionSheet];
+    for (MDCActionSheetItemTableViewCell *cell in cells) {
+      // Then
+      XCTAssertEqualObjects(cell.inkTouchController.defaultInkView.inkColor, color);
+    }
+  }
+}
+
+- (void)testSetActionFont {
+  // Given
+  UIFont *actionFont = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline];
+
+  // When
+  self.actionSheet.actionFont = actionFont;
+  NSArray *cells = [MDCActionSheetTestHelper getCellsFromActionSheet:self.actionSheet];
+  XCTAssertNotEqual(cells.count, 0U);
+  for (MDCActionSheetItemTableViewCell *cell in cells) {
+    // Then
+    XCTAssertEqual(cell.actionLabel.font, actionFont);
+  }
+}
+
+@end
diff --git a/components/ActionSheet/tests/unit/MDCActionSheetTest.m b/components/ActionSheet/tests/unit/MDCActionSheetTest.m
index a1144b5..c1f9a28 100644
--- a/components/ActionSheet/tests/unit/MDCActionSheetTest.m
+++ b/components/ActionSheet/tests/unit/MDCActionSheetTest.m
@@ -12,25 +12,35 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#import "MaterialActionSheet.h"
+#import "MaterialMath.h"
 
 #import <XCTest/XCTest.h>
 
 #import "../../src/private/MDCActionSheetHeaderView.h"
+#import "MDCActionSheetTestHelper.h"
+
+static const CGFloat kSafeAreaAmount = 20.f;
 
 @interface MDCActionSheetHeaderView (Testing)
 @property(nonatomic, strong) UILabel *titleLabel;
 @property(nonatomic, strong) UILabel *messageLabel;
 @end
 
-@interface MDCActionSheetController (Testing)
-@property(nonatomic, strong) MDCActionSheetHeaderView *header;
-@end
-
 @interface MDCActionSheetTest : XCTestCase
 @property(nonatomic, strong) MDCActionSheetController *actionSheet;
 @end
 
+@interface MDCFakeView : UIView
+@end
+
+@implementation MDCFakeView
+
+- (UIEdgeInsets)safeAreaInsets {
+  return UIEdgeInsetsMake(kSafeAreaAmount, kSafeAreaAmount, kSafeAreaAmount, kSafeAreaAmount);
+}
+
+@end
+
 @implementation MDCActionSheetTest
 
 - (void)setUp {
@@ -89,4 +99,297 @@
   XCTAssertEqualObjects(messageColor, expectedMessageColor);
 }
 
+- (void)testCustomMessageColor {
+  // Given
+  self.actionSheet.message = @"Test message";
+
+  NSArray *colors = [MDCActionSheetTestHelper colorsToTest];
+  for (UIColor *color in colors) {
+    // When
+    self.actionSheet.messageTextColor = color;
+
+    // Then
+    XCTAssertEqualObjects(self.actionSheet.header.messageLabel.textColor, color);
+  }
+}
+
+- (void)testCustomTitleColor {
+  // Given
+  self.actionSheet.title = @"Test title";
+
+  NSArray *colors = [MDCActionSheetTestHelper colorsToTest];
+  for (UIColor *color in colors) {
+    // When
+    self.actionSheet.titleTextColor = color;
+
+    // Then
+    XCTAssertEqualObjects(self.actionSheet.header.titleLabel.textColor, color);
+  }
+}
+
+- (void)testCustomBackgroundColor {
+  // Given
+  NSArray *colors = [MDCActionSheetTestHelper colorsToTest];
+  for (UIColor *color in colors) {
+    // When
+    self.actionSheet.backgroundColor = color;
+
+    // Then
+    XCTAssertEqualObjects(self.actionSheet.backgroundColor, color);
+  }
+}
+
+- (void)testTitleAndMessageColorCorrectAlpha {
+  // Given
+  self.actionSheet.title = @"Test title";
+  self.actionSheet.message = @"Test message";
+  UIColor *titleColor = UIColor.blackColor;
+  UIColor *messageColor = UIColor.blackColor;
+
+  // When
+  UIColor *titleColorChangeAlpha = [titleColor colorWithAlphaComponent:0.6f];
+  UIColor *messageColorChangeAlpha = [messageColor colorWithAlphaComponent:0.5f];
+
+  self.actionSheet.titleTextColor = titleColorChangeAlpha;
+  self.actionSheet.messageTextColor = messageColorChangeAlpha;
+
+  // Then
+  XCTAssertFalse([titleColor isEqual:self.actionSheet.header.titleLabel.textColor]);
+  XCTAssertFalse([messageColor isEqual:self.actionSheet.header.messageLabel.textColor]);
+}
+
+- (void)testSetTitleAndMessageAfterCustomColorsSet {
+  // Given
+  UIColor *titleColor = UIColor.blueColor;
+  UIColor *messageColor = UIColor.redColor;
+
+  // When
+  self.actionSheet.titleTextColor = titleColor;
+  self.actionSheet.messageTextColor = messageColor;
+  self.actionSheet.title = @"Test title";
+  self.actionSheet.message = @"Test message";
+
+  // Then
+  XCTAssertEqualObjects(self.actionSheet.header.titleLabel.textColor, titleColor);
+  XCTAssertEqualObjects(self.actionSheet.header.messageLabel.textColor, messageColor);
+}
+
+- (void)testTitleCustomDoesNotChangeAfterSetMessage {
+  // Given
+  UIColor *titleColor = [UIColor.blueColor colorWithAlphaComponent:0.6f];
+  self.actionSheet.title = @"Test title";
+
+  // When
+  self.actionSheet.titleTextColor = titleColor;
+  self.actionSheet.message = @"Test message";
+
+  // Then
+  XCTAssertEqualObjects(self.actionSheet.header.titleLabel.textColor, titleColor);
+}
+
+- (void)testSetNilTitleAndMessageColor {
+  // Given
+  self.actionSheet.title = @"Test title";
+  self.actionSheet.message = @"Test message";
+
+  // When
+  self.actionSheet.titleTextColor = nil;
+  self.actionSheet.messageTextColor = nil;
+
+  // Then
+  XCTAssertEqualObjects(self.actionSheet.header.titleLabel.textColor,
+                        [UIColor.blackColor colorWithAlphaComponent:0.87f]);
+  XCTAssertEqualObjects(self.actionSheet.header.messageLabel.textColor,
+                        [UIColor.blackColor colorWithAlphaComponent:0.6f]);
+}
+
+#pragma mark - Opening height
+
+- (CGRect)setUpActionSheetWithHeight:(CGFloat)height
+                            andTitle:(NSString *)title
+                          andMessage:(NSString *)message {
+  // Given
+  CGRect viewRect = CGRectMake(0, 0, 200, height);
+  self.actionSheet.view.bounds = viewRect;
+  self.actionSheet.title = title;
+  self.actionSheet.message = message;
+
+  // When
+  [MDCActionSheetTestHelper addNumberOfActions:100 toActionSheet:self.actionSheet];
+  [self.actionSheet.view setNeedsLayout];
+  [self.actionSheet.view layoutIfNeeded];
+  return viewRect;
+}
+
+- (void)testOpeningHeightWithTitle {
+  // Given
+  CGFloat fakeHeight = 500;
+  CGRect viewRect = [self setUpActionSheetWithHeight:fakeHeight
+                                            andTitle:@"Test Title"
+                                          andMessage:nil];
+
+  CGFloat cellHeight =
+      self.actionSheet.tableView.contentSize.height / (CGFloat)self.actionSheet.actions.count;
+  cellHeight = MDCCeil(cellHeight);
+  CGFloat halfCellHeight = cellHeight * 0.5f;
+  CGFloat headerHeight = CGRectGetHeight(self.actionSheet.header.frame);
+
+  for (NSInteger additionalHeight = 0; additionalHeight < cellHeight; ++additionalHeight) {
+    // When
+    viewRect.size.height = fakeHeight + additionalHeight;
+    self.actionSheet.view.bounds = viewRect;
+    [self.actionSheet.view setNeedsLayout];
+    [self.actionSheet.view layoutIfNeeded];
+
+    // Then
+    CGFloat expectedHeight = [self.actionSheet openingSheetHeight];
+    CGFloat expectedMinusHeader = expectedHeight - headerHeight;
+    // Action sheet should show half of the allowed actions but the full last action
+    XCTAssertEqualWithAccuracy(fmod(expectedMinusHeader, halfCellHeight), 0, 0.001);
+    XCTAssertNotEqualWithAccuracy(fmod(expectedMinusHeader, cellHeight), 0, 0.001);
+  }
+}
+
+- (void)testOpeningHeightWithtTitleAndSmallMessage {
+  // Given
+  CGFloat fakeHeight = 500;
+  CGRect viewRect = [self setUpActionSheetWithHeight:fakeHeight
+                                            andTitle:@"Test title"
+                                          andMessage:@"Test message"];
+
+  CGFloat cellHeight =
+      self.actionSheet.tableView.contentSize.height / (CGFloat)self.actionSheet.actions.count;
+  cellHeight = MDCCeil(cellHeight);
+  CGFloat halfCellHeight = cellHeight * 0.5f;
+  CGFloat headerHeight = CGRectGetHeight(self.actionSheet.header.frame);
+
+  for (NSInteger additionalHeight = 0; additionalHeight < cellHeight; ++additionalHeight) {
+    // When
+    viewRect.size.height = fakeHeight + additionalHeight;
+    self.actionSheet.view.bounds = viewRect;
+    [self.actionSheet.view setNeedsLayout];
+    [self.actionSheet.view layoutIfNeeded];
+
+    // Then
+    CGFloat expectedHeight = [self.actionSheet openingSheetHeight];
+    CGFloat expectedMinusHeader = expectedHeight - headerHeight;
+    // Action sheet should show half of the allowed actions but the full last action
+    XCTAssertEqualWithAccuracy(fmod(expectedMinusHeader, halfCellHeight), 0, 0.001);
+    XCTAssertNotEqualWithAccuracy(fmod(expectedMinusHeader, cellHeight), 0, 0.001);
+  }
+}
+
+- (void)testOpeningHeightWithTitleAndLargeMessage {
+  // Given
+  CGFloat fakeHeight = 500;
+  NSString *first = @"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur ultricies";
+  NSString *second = @"diam libero, eget porta arcu feugiat sit amet Maecenas placerat felis sed ";
+  NSString *third = @"risusnmaximus tempus.Integer feugiat, augue in pellentesque dictum, justo ";
+  NSString *fourth = @"erat ultricies leo, quis eros dictum mi. In finibus vulputate eros, auctor";
+  NSString *messageString = [NSString stringWithFormat:@"%@%@%@%@", first, second, third, fourth];
+  self.actionSheet.message = messageString;
+  CGRect viewRect = [self setUpActionSheetWithHeight:fakeHeight
+                                            andTitle:@"Test title"
+                                          andMessage:messageString];
+
+  CGFloat cellHeight =
+      self.actionSheet.tableView.contentSize.height / (CGFloat)self.actionSheet.actions.count;
+  cellHeight = MDCCeil(cellHeight);
+  CGFloat halfCellHeight = cellHeight * 0.5f;
+  CGFloat headerHeight = CGRectGetHeight(self.actionSheet.header.frame);
+
+  for (NSInteger additionalHeight = 0; additionalHeight < cellHeight; ++additionalHeight) {
+    // When
+    viewRect.size.height = fakeHeight + additionalHeight;
+    self.actionSheet.view.bounds = viewRect;
+    [self.actionSheet.view setNeedsLayout];
+    [self.actionSheet.view layoutIfNeeded];
+
+    // Then
+    CGFloat expectedHeight = [self.actionSheet openingSheetHeight];
+    CGFloat expectedMinusHeader = expectedHeight - headerHeight;
+    // Action sheet should show half of the allowed actions but the full last action
+    XCTAssertEqualWithAccuracy(fmod(expectedMinusHeader, halfCellHeight), 0, 0.001);
+    XCTAssertNotEqualWithAccuracy(fmod(expectedMinusHeader, cellHeight), 0, 0.001);
+  }
+}
+
+- (void)testOpeningHeightWithSafeArea {
+  // Given
+  CGFloat fakeHeight = 500;
+  CGRect viewRect = [self setUpActionSheetWithHeight:fakeHeight andTitle:nil andMessage:nil];
+
+  CGFloat cellHeight =
+      self.actionSheet.tableView.contentSize.height / (CGFloat)self.actionSheet.actions.count;
+  cellHeight = MDCCeil(cellHeight);
+  CGFloat halfCellHeight = cellHeight * 0.5f;
+  CGFloat headerHeight = CGRectGetHeight(self.actionSheet.header.frame);
+
+  for (NSInteger additionalHeight = 0; additionalHeight < cellHeight; ++additionalHeight) {
+    // When
+    viewRect.size.height = fakeHeight + additionalHeight;
+    self.actionSheet.view.bounds = viewRect;
+    [self.actionSheet.view setNeedsLayout];
+    [self.actionSheet.view layoutIfNeeded];
+
+    // Then
+    CGFloat expectedHeight = [self.actionSheet openingSheetHeight];
+    CGFloat expectedMinusHeader = expectedHeight - headerHeight;
+    // Action sheet should show half of the allowed actions but the full last action
+    XCTAssertEqualWithAccuracy(fmod(expectedMinusHeader, halfCellHeight), 0, 0.001);
+    XCTAssertNotEqualWithAccuracy(fmod(expectedMinusHeader, cellHeight), 0, 0.001);
+  }
+}
+
+- (void)testOpeningHeightNoHeader {
+  // Given
+  CGFloat fakeHeight = 500;
+  CGRect viewRect = [self setUpActionSheetWithHeight:fakeHeight andTitle:nil andMessage:nil];
+
+  CGFloat cellHeight =
+      self.actionSheet.tableView.contentSize.height / (CGFloat)self.actionSheet.actions.count;
+  cellHeight = MDCCeil(cellHeight);
+  CGFloat halfCellHeight = cellHeight * 0.5f;
+  CGFloat headerHeight = CGRectGetHeight(self.actionSheet.header.frame);
+
+  for (NSInteger additionalHeight = 0; additionalHeight < cellHeight; ++additionalHeight) {
+    // When
+    viewRect.size.height = fakeHeight + additionalHeight;
+    self.actionSheet.view.bounds = viewRect;
+    [self.actionSheet.view setNeedsLayout];
+    [self.actionSheet.view layoutIfNeeded];
+
+    // Then
+    CGFloat expectedHeight = [self.actionSheet openingSheetHeight];
+    CGFloat expectedMinusHeader = expectedHeight - headerHeight;
+    // Action sheet should show half of the allowed actions but the full last action
+    XCTAssertEqualWithAccuracy(fmod(expectedMinusHeader, halfCellHeight), 0, 0.001);
+    XCTAssertNotEqualWithAccuracy(fmod(expectedMinusHeader, cellHeight), 0, 0.001);
+  }
+}
+
+#pragma mark - Fonts
+
+- (void)testSetTitleFont {
+  // Given
+  UIFont *titleFont = [UIFont preferredFontForTextStyle:UIFontTextStyleCallout];
+
+  // When
+  self.actionSheet.titleFont = titleFont;
+
+  // Then
+  XCTAssertEqual(self.actionSheet.header.titleLabel.font, titleFont);
+}
+
+- (void)testSetMessageFont {
+  // Given
+  UIFont *messageFont = [UIFont preferredFontForTextStyle:UIFontTextStyleCaption1];
+
+  // When
+  self.actionSheet.messageFont = messageFont;
+
+  // Then
+  XCTAssertEqual(self.actionSheet.header.messageLabel.font, messageFont);
+}
+
 @end
diff --git a/components/ActionSheet/tests/unit/MDCActionSheetTestHelper.h b/components/ActionSheet/tests/unit/MDCActionSheetTestHelper.h
new file mode 100644
index 0000000..8e3f15a
--- /dev/null
+++ b/components/ActionSheet/tests/unit/MDCActionSheetTestHelper.h
@@ -0,0 +1,38 @@
+// Copyright 2018-present the Material Components for iOS authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#import "MaterialActionSheet.h"
+
+#import <XCTest/XCTest.h>
+
+@class MDCActionSheetHeaderView;
+@class MDCActionSheetItemTableViewCell;
+
+@interface MDCActionSheetController (Testing)
+@property(nonatomic, strong) UITableView *tableView;
+@property(nonatomic, strong) MDCActionSheetHeaderView *header;
+- (CGFloat)openingSheetHeight;
+@end
+
+@interface MDCActionSheetTestHelper : NSObject
+
++ (NSArray *)colorsToTest;
+
++ (void)addNumberOfActions:(NSUInteger)actionsCount
+             toActionSheet:(MDCActionSheetController *)actionSheet;
+
++ (NSArray<MDCActionSheetItemTableViewCell *> *)getCellsFromActionSheet:
+    (MDCActionSheetController *)actionSheet;
+
+@end
diff --git a/components/ActionSheet/tests/unit/MDCActionSheetTestHelper.m b/components/ActionSheet/tests/unit/MDCActionSheetTestHelper.m
new file mode 100644
index 0000000..64f5e53
--- /dev/null
+++ b/components/ActionSheet/tests/unit/MDCActionSheetTestHelper.m
@@ -0,0 +1,61 @@
+// Copyright 2018-present the Material Components for iOS authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#import "MDCActionSheetTestHelper.h"
+
+#import <CoreImage/CoreImage.h>
+
+#import "../../src/private/MDCActionSheetHeaderView.h"
+#import "../../src/private/MDCActionSheetItemTableViewCell.h"
+
+@implementation MDCActionSheetTestHelper
+
++ (NSArray *)colorsToTest {
+  UIColor *rgbColor = [UIColor colorWithRed:0.7f green:0.7f blue:0.7f alpha:0.7f];
+  UIColor *hsbColor = [UIColor colorWithHue:0.8f saturation:0.8f brightness:0.8f alpha:0.8f];
+  UIColor *blackWithAlpha = [UIColor.greenColor colorWithAlphaComponent:0.8f];
+  UIColor *black = UIColor.blackColor;
+  CIColor *ciColor = [[CIColor alloc] initWithColor:UIColor.blackColor];
+  UIColor *uiColorFromCIColor = [UIColor colorWithCIColor:ciColor];
+  UIColor *whiteColor = [UIColor colorWithWhite:0.5f alpha:0.5f];
+  return @[ rgbColor, hsbColor, blackWithAlpha, black, uiColorFromCIColor, whiteColor ];
+}
+
++ (void)addNumberOfActions:(NSUInteger)actionsCount
+             toActionSheet:(MDCActionSheetController *)actionSheet {
+  for (NSUInteger actionIndex = 0; actionIndex < actionsCount; ++actionIndex) {
+    NSString *actionTitle = [NSString stringWithFormat:@"Action #%@", @(actionIndex)];
+    MDCActionSheetAction *action = [MDCActionSheetAction actionWithTitle:actionTitle
+                                                                   image:nil
+                                                                 handler:nil];
+    [actionSheet addAction:action];
+  }
+}
+
++ (NSArray<MDCActionSheetItemTableViewCell *> *)getCellsFromActionSheet:
+    (MDCActionSheetController *)actionSheet {
+  NSMutableArray *cellsArray = [[NSMutableArray alloc] init];
+  [MDCActionSheetTestHelper addNumberOfActions:10 toActionSheet:actionSheet];
+  NSUInteger cellsCount = actionSheet.actions.count;
+  UITableView *table = actionSheet.tableView;
+  for (NSUInteger cellIndex = 0; cellIndex < cellsCount; ++cellIndex) {
+    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:cellIndex inSection:0];
+    UITableViewCell *cell = [table.dataSource tableView:table cellForRowAtIndexPath:indexPath];
+    MDCActionSheetItemTableViewCell *actionCell = (MDCActionSheetItemTableViewCell *)cell;
+    [cellsArray addObject:actionCell];
+  }
+  return cellsArray;
+}
+
+@end
diff --git a/components/ActionSheet/tests/unit/MDCActionSheetThemeTest.m b/components/ActionSheet/tests/unit/MDCActionSheetThemeTest.m
new file mode 100644
index 0000000..487a5c6
--- /dev/null
+++ b/components/ActionSheet/tests/unit/MDCActionSheetThemeTest.m
@@ -0,0 +1,147 @@
+// Copyright 2018-present the Material Components for iOS authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#import <XCTest/XCTest.h>
+
+#import "../../src/private/MDCActionSheetHeaderView.h"
+#import "../../src/private/MDCActionSheetItemTableViewCell.h"
+#import "MDCActionSheetTestHelper.h"
+#import "MaterialActionSheet+ColorThemer.h"
+#import "MaterialActionSheet+TypographyThemer.h"
+
+static const CGFloat kHighAlpha = 0.87f;
+static const CGFloat kMediumAlpha = 0.6f;
+static const CGFloat kInkAlpha = 16.f;
+
+@interface MDCActionSheetHeaderView (Testing)
+@property(nonatomic, strong) UILabel *titleLabel;
+@property(nonatomic, strong) UILabel *messageLabel;
+@end
+
+@interface MDCActionSheetItemTableViewCell (Testing)
+@property(nonatomic, strong) UILabel *actionLabel;
+@property(nonatomic, strong) UIImageView *actionImageView;
+@property(nonatomic, strong) MDCInkTouchController *inkTouchController;
+@end
+
+@interface MDCActionSheetThemeTest : XCTestCase
+@property(nonatomic, strong) MDCActionSheetController *actionSheet;
+@property(nonatomic, strong) MDCSemanticColorScheme *colorScheme;
+@property(nonatomic, strong) MDCTypographyScheme *typographyScheme;
+@end
+
+@implementation MDCActionSheetThemeTest
+
+- (void)setUp {
+  [super setUp];
+
+  self.actionSheet = [[MDCActionSheetController alloc] init];
+  self.colorScheme = [[MDCSemanticColorScheme alloc] init];
+  UIColor *surface = UIColor.blueColor;
+  UIColor *onSurface = UIColor.redColor;
+  self.colorScheme.primaryColor = surface;
+  self.colorScheme.onPrimaryColor = onSurface;
+  self.typographyScheme = [[MDCTypographyScheme alloc] init];
+  UIFont *subtitle = [UIFont systemFontOfSize:12.0 weight:UIFontWeightBold];
+  UIFont *body1 = [UIFont systemFontOfSize:8.0 weight:UIFontWeightThin];
+  UIFont *body2 = [UIFont systemFontOfSize:10.0 weight:UIFontWeightLight];
+  self.typographyScheme.subtitle1 = subtitle;
+  self.typographyScheme.body1 = body1;
+  self.typographyScheme.body2 = body2;
+}
+
+#pragma mark - Header test
+
+- (void)testApplyColorThemerWithTitleAndMessage {
+  // Given
+  self.actionSheet.title = @"Test title";
+  self.actionSheet.message = @"Test message";
+
+  // When
+  [MDCActionSheetColorThemer applySemanticColorScheme:self.colorScheme
+                              toActionSheetController:self.actionSheet];
+
+  // Then
+  XCTAssertEqualObjects(self.actionSheet.header.titleLabel.textColor,
+                        [self.colorScheme.onSurfaceColor colorWithAlphaComponent:kHighAlpha]);
+  XCTAssertEqualObjects(self.actionSheet.header.messageLabel.textColor,
+                        [self.colorScheme.onSurfaceColor colorWithAlphaComponent:kMediumAlpha]);
+}
+
+- (void)testApplyThemerWithOnlyTitle {
+  // Given
+  self.actionSheet.title = @"Test title";
+
+  // When
+  [MDCActionSheetColorThemer applySemanticColorScheme:self.colorScheme
+                              toActionSheetController:self.actionSheet];
+
+  // Then
+  XCTAssertEqualObjects(self.actionSheet.header.titleLabel.textColor,
+                        [self.colorScheme.onSurfaceColor colorWithAlphaComponent:kMediumAlpha]);
+}
+
+- (void)testApplyThemerWithOnlyMessage {
+  // Given
+  self.actionSheet.message = @"Test message";
+
+  // When
+  [MDCActionSheetColorThemer applySemanticColorScheme:self.colorScheme
+                              toActionSheetController:self.actionSheet];
+
+  // Then
+  XCTAssertEqualObjects(self.actionSheet.header.messageLabel.textColor,
+                        [self.colorScheme.onSurfaceColor colorWithAlphaComponent:kMediumAlpha]);
+}
+
+#pragma mark - default test
+
+- (void)testApplyColorTheme {
+  // When
+  [MDCActionSheetColorThemer applySemanticColorScheme:self.colorScheme
+                              toActionSheetController:self.actionSheet];
+  NSArray *cells = [MDCActionSheetTestHelper getCellsFromActionSheet:self.actionSheet];
+
+  // Then
+  XCTAssertNotEqual(cells.count, 0U);
+  for (MDCActionSheetItemTableViewCell *cell in cells) {
+    XCTAssertEqualObjects(cell.actionImageView.tintColor,
+                          [self.colorScheme.onSurfaceColor colorWithAlphaComponent:kMediumAlpha]);
+    XCTAssertEqualObjects(cell.actionLabel.textColor,
+                          [self.colorScheme.onSurfaceColor colorWithAlphaComponent:kHighAlpha]);
+    XCTAssertEqualObjects(cell.inkTouchController.defaultInkView.inkColor,
+                          [self.colorScheme.onSurfaceColor colorWithAlphaComponent:kInkAlpha]);
+  }
+}
+
+- (void)testApplyTypographyTheme {
+  // Given
+  self.actionSheet.title = @"Test title";
+  self.actionSheet.message = @"Test message";
+
+  // When
+  [MDCActionSheetTypographyThemer applyTypographyScheme:self.typographyScheme
+                                toActionSheetController:self.actionSheet];
+  NSArray *cells = [MDCActionSheetTestHelper getCellsFromActionSheet:self.actionSheet];
+
+  // Then
+  XCTAssertEqualObjects(self.actionSheet.header.titleLabel.font, self.typographyScheme.subtitle1);
+  XCTAssertEqualObjects(self.actionSheet.header.messageLabel.font, self.typographyScheme.body2);
+  XCTAssertNotEqual(cells.count, 0U);
+  for (MDCActionSheetItemTableViewCell *cell in cells) {
+    XCTAssertEqualObjects(cell.actionLabel.font, self.typographyScheme.body1);
+  }
+}
+
+@end
diff --git a/components/AppBar/README.md b/components/AppBar/README.md
index 1ef5ff1..b7fe30a 100644
--- a/components/AppBar/README.md
+++ b/components/AppBar/README.md
@@ -775,6 +775,12 @@
 
 // Step 3
 -  appBar.addSubviewsToParent()
++  // Match the width of the parent view.
++  CGRect frame = appBarViewController.view.frame;
++  frame.origin.x = 0;
++  frame.size.width = appBarViewController.parentViewController.view.bounds.size.width;
++  appBarViewController.view.frame = frame;
++
 +  view.addSubview(appBarViewController.view)
 +  appBarViewController.didMove(toParentViewController: self)
 ```
diff --git a/components/AppBar/docs/migration-guide-appbar-appbarviewcontroller.md b/components/AppBar/docs/migration-guide-appbar-appbarviewcontroller.md
index 4347c21..e8ddc71 100644
--- a/components/AppBar/docs/migration-guide-appbar-appbarviewcontroller.md
+++ b/components/AppBar/docs/migration-guide-appbar-appbarviewcontroller.md
@@ -19,6 +19,12 @@
 
 // Step 3
 -  appBar.addSubviewsToParent()
++  // Match the width of the parent view.
++  CGRect frame = appBarViewController.view.frame;
++  frame.origin.x = 0;
++  frame.size.width = appBarViewController.parentViewController.view.bounds.size.width;
++  appBarViewController.view.frame = frame;
++
 +  view.addSubview(appBarViewController.view)
 +  appBarViewController.didMove(toParentViewController: self)
 ```
diff --git a/components/AppBar/examples/AppBarManualTabsExample.swift b/components/AppBar/examples/AppBarManualTabsExample.swift
new file mode 100644
index 0000000..8f255cd
--- /dev/null
+++ b/components/AppBar/examples/AppBarManualTabsExample.swift
@@ -0,0 +1,208 @@
+// Copyright 2018-present the Material Components for iOS authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import UIKit
+import CoreGraphics
+
+import MaterialComponents.MaterialColorScheme
+import MaterialComponents.MaterialAppBar
+import MaterialComponents.MaterialAppBar_ColorThemer
+import MaterialComponents.MaterialAppBar_TypographyThemer
+import MaterialComponents.MaterialTabs
+import MaterialComponents.MaterialTypographyScheme
+import MaterialComponents.MaterialFlexibleHeader_CanAlwaysExpandToMaximumHeight
+
+// An example that demonstrates the behavior of an App Bar with Tabs and manually swapped tab view
+// controllers. This example is distinct from a typical tab bar view controller in that it does not
+// make use of a horizontally-paging scroll view. This example also makes use of the
+// canAlwaysExpandToMaximumHeight API to allow the header to maintain its expanded state when
+// swapping between tabs.
+class AppBarManualTabsExample: UIViewController {
+
+  lazy var appBarViewController: MDCAppBarViewController = self.makeAppBar()
+  var colorScheme = MDCSemanticColorScheme()
+  var typographyScheme = MDCTypographyScheme()
+
+  fileprivate let firstTab = SimpleTableViewController()
+  fileprivate let secondTab = SimpleTableViewController()
+  private var currentTab: SimpleTableViewController? = nil
+
+  lazy var tabBar: MDCTabBar = {
+    let tabBar = MDCTabBar()
+
+    tabBar.items = [
+      UITabBarItem(title: "First", image: nil, tag:0),
+      UITabBarItem(title: "Second", image: nil, tag:1)
+    ]
+
+    tabBar.delegate = self
+    return tabBar
+  }()
+
+  override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
+    super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
+
+    self.title = "Tab Bar Example"
+    self.firstTab.title = "First"
+    self.secondTab.title = "Second"
+  }
+
+  required init?(coder aDecoder: NSCoder) {
+    fatalError("init(coder:) has not been implemented")
+  }
+
+  override func viewDidLoad() {
+    super.viewDidLoad()
+
+    MDCAppBarColorThemer.applyColorScheme(colorScheme, to: appBarViewController)
+    MDCAppBarTypographyThemer.applyTypographyScheme(typographyScheme, to: appBarViewController)
+
+    // Need to update the status bar style after applying the theme.
+    setNeedsStatusBarAppearanceUpdate()
+
+    view.backgroundColor = colorScheme.backgroundColor
+    view.addSubview(appBarViewController.view)
+    appBarViewController.didMove(toParentViewController: self)
+
+    switchToTab(firstTab)
+  }
+
+  fileprivate func switchToTab(_ tab: SimpleTableViewController) {
+    appBarViewController.headerView.trackingScrollWillChange(toScroll: tab.tableView)
+
+    if let currentTab = currentTab {
+      currentTab.headerView = nil
+      currentTab.willMove(toParentViewController: nil)
+      currentTab.view.removeFromSuperview()
+      currentTab.removeFromParentViewController()
+    }
+
+    if let tabView = tab.view {
+      tabView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
+      tabView.frame = view.bounds
+    }
+
+    view.addSubview(tab.tableView)
+    view.sendSubview(toBack: tab.tableView)
+    tab.didMove(toParentViewController: self)
+
+    tab.headerView = appBarViewController.headerView
+
+    appBarViewController.headerView.trackingScrollView = tab.tableView
+    currentTab = tab
+  }
+
+  @objc func changeAlignmentDidTouch(sender: UIButton) {
+    firstTab.title = "First"
+    switchToTab(firstTab)
+  }
+
+  @objc func changeAppearance(fromSender sender: UIButton) {
+    secondTab.title = "Second"
+    switchToTab(secondTab)
+  }
+
+  // MARK: Private
+
+  private func makeAppBar() -> MDCAppBarViewController {
+    let appBarViewController = MDCAppBarViewController()
+
+    addChildViewController(appBarViewController)
+
+    // Give the tab bar enough height to accomodate all possible item appearances.
+    appBarViewController.headerView.minMaxHeightIncludesSafeArea = false
+    appBarViewController.inferTopSafeAreaInsetFromViewController = true
+    appBarViewController.headerView.canAlwaysExpandToMaximumHeight = true
+    appBarViewController.headerView.sharedWithManyScrollViews = true
+
+    appBarViewController.headerView.minimumHeight = 56
+    appBarViewController.headerView.maximumHeight = 128
+
+    appBarViewController.headerStackView.bottomBar = tabBar
+
+    return appBarViewController
+  }
+
+  override var childViewControllerForStatusBarStyle: UIViewController? {
+    return appBarViewController
+  }
+}
+
+extension AppBarManualTabsExample: MDCTabBarDelegate {
+  func tabBar(_ tabBar: MDCTabBar, didSelect item: UITabBarItem) {
+    if item.tag == 0 {
+      switchToTab(firstTab)
+    } else {
+      switchToTab(secondTab)
+    }
+  }
+}
+
+extension AppBarManualTabsExample {
+
+  class func catalogMetadata() -> [String: Any] {
+    return [
+      "breadcrumbs": ["App Bar", "Manual tabs"],
+      "primaryDemo": false,
+      "presentable": true,
+    ]
+  }
+
+  func catalogShouldHideNavigation() -> Bool {
+    return true
+  }
+}
+
+private class SimpleTableViewController: UITableViewController {
+
+  var headerView: MDCFlexibleHeaderView?
+
+  override func viewDidLoad() {
+    super.viewDidLoad()
+
+    tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
+    tableView.delegate = self
+    tableView.dataSource = self
+  }
+
+  override func numberOfSections(in tableView: UITableView) -> Int {
+    return 1
+  }
+
+  override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+    return 100
+  }
+
+  override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
+    cell.textLabel!.text = "\(title!): Row \(indexPath.item)"
+    return cell
+  }
+
+  override func scrollViewDidScroll(_ scrollView: UIScrollView) {
+    headerView?.trackingScrollDidScroll()
+  }
+
+  override func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
+    headerView?.trackingScrollDidEndDecelerating()
+  }
+
+  override func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
+    headerView?.trackingScrollWillEndDragging(withVelocity: velocity, targetContentOffset: targetContentOffset)
+  }
+
+  override func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
+    headerView?.trackingScrollDidEndDraggingWillDecelerate(decelerate)
+  }
+}
diff --git a/components/AppBar/src/MDCAppBarViewController.h b/components/AppBar/src/MDCAppBarViewController.h
index 52f964c..d2ee14f 100644
--- a/components/AppBar/src/MDCAppBarViewController.h
+++ b/components/AppBar/src/MDCAppBarViewController.h
@@ -107,26 +107,3 @@
 @property(nonatomic) BOOL inferTopSafeAreaInsetFromViewController;
 
 @end
-
-/**
- The MDCAppBarTextColorAccessibilityMutator class creates an external object with which to work on
- an instance of a Material App Bar to activate and ensure accessibility on its title and buttons.
-
- ### Dependencies
-
- Material AppBarTextColorAccessibilityMutator depends on the AppBar material component and
- MDFTextAccessibility Framework.
-
- @note This API will be deprecated with no replacement.
- */
-__deprecated_msg("Use themers and MDFTextAccessibility directly instead.")
-@interface MDCAppBarTextColorAccessibilityMutator : NSObject
-
-/**
- Mutates title text color and navigation items' tint colors based on background color of
- app bar's navigation bar or header view background color.
- */
-- (void)mutate:(nonnull MDCAppBar *)appBar
-__deprecated_msg("Use themers and MDFTextAccessibility instead.");
-
-@end
diff --git a/components/AppBar/src/MDCAppBarViewController.m b/components/AppBar/src/MDCAppBarViewController.m
index 47860d9..2e59af4 100644
--- a/components/AppBar/src/MDCAppBarViewController.m
+++ b/components/AppBar/src/MDCAppBarViewController.m
@@ -324,40 +324,3 @@
 }
 
 @end
-
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated-implementations"
-@implementation MDCAppBarTextColorAccessibilityMutator
-
-- (void)mutate:(nonnull MDCAppBar *)appBar {
-  // Determine what is the appropriate background color
-  // Because navigation bar renders above headerview, it takes presedence
-  UIColor *backgroundColor = appBar.navigationBar.backgroundColor ?:
-  appBar.headerViewController.headerView.backgroundColor;
-  if (!backgroundColor) {
-    return;
-  }
-
-  // Update title label color based on navigationBar/headerView backgroundColor
-  NSMutableDictionary *textAttr =
-  [NSMutableDictionary dictionaryWithDictionary:[appBar.navigationBar titleTextAttributes]];
-  MDFTextAccessibilityOptions options = 0;
-  BOOL isLarge =
-  [MDCTypography isLargeForContrastRatios:[textAttr objectForKey:NSFontAttributeName]];
-  if (isLarge) {
-    options |= MDFTextAccessibilityOptionsLargeFont;
-  }
-  UIColor *textColor =
-  [MDFTextAccessibility textColorOnBackgroundColor:backgroundColor
-                                   targetTextAlpha:1.0
-                                           options:options];
-
-  [textAttr setObject:textColor forKey:NSForegroundColorAttributeName];
-  [appBar.navigationBar setTitleTextAttributes:textAttr];
-
-  // Update button's tint color based on navigationBar backgroundColor
-  appBar.navigationBar.tintColor = textColor;
-}
-
-@end
-#pragma clang diagnostic pop
diff --git a/components/AppBar/tests/unit/AppBarAccessibilityMutatorTestColorTest.swift b/components/AppBar/tests/unit/AppBarAccessibilityMutatorTestColorTest.swift
deleted file mode 100644
index b1b37a0..0000000
--- a/components/AppBar/tests/unit/AppBarAccessibilityMutatorTestColorTest.swift
+++ /dev/null
@@ -1,144 +0,0 @@
-// Copyright 2016-present the Material Components for iOS authors. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-import XCTest
-import MaterialComponents.MaterialAppBar
-import MDFTextAccessibility
-
-// Tests confirming that the App Bar Accessibility Mutator correctly changes title font color and
-// tint color on App Bar's |navigationBar| to meet accepted accessibility values defined by
-// MDFTextAccessibility
-
-class AppBarAccessibilityMutatorTestColorTest: XCTestCase {
-
-  var appBar: MDCAppBar!
-  var mutator: MDCAppBarTextColorAccessibilityMutator!
-
-  override func setUp() {
-    super.setUp()
-    appBar = MDCAppBar()
-    mutator = MDCAppBarTextColorAccessibilityMutator()
-  }
-
-  func testDarkNavigationBarBackground() {
-    // Given
-    appBar.navigationBar.backgroundColor = UIColor.black
-
-    // When
-    mutator.mutate(appBar)
-
-    // Then
-    let fontColor =
-        appBar.navigationBar.titleTextAttributes![NSForegroundColorAttributeName] as! UIColor
-    let tintColor = appBar.navigationBar.tintColor
-    let accessibleColor = MDFTextAccessibility.textColor(onBackgroundColor: UIColor.black,
-                                                                          targetTextAlpha: 1.0,
-                                                                          font: nil)
-
-    XCTAssertEqual(fontColor, accessibleColor)
-    XCTAssertEqual(tintColor, accessibleColor)
-  }
-
-  func testLightNavigationBarBackground() {
-    // Given
-    appBar.navigationBar.backgroundColor = UIColor.white
-
-    // When
-    mutator.mutate(appBar)
-
-    // Then
-    let fontColor =
-        appBar.navigationBar.titleTextAttributes![NSForegroundColorAttributeName] as! UIColor
-    let tintColor = appBar.navigationBar.tintColor
-    let accessibleColor = MDFTextAccessibility.textColor(onBackgroundColor: UIColor.white,
-                                                                          targetTextAlpha: 1.0,
-                                                                          font: nil)
-    XCTAssertEqual(fontColor, accessibleColor)
-    XCTAssertEqual(tintColor, accessibleColor)
-  }
-
-  func testDarkHeaderViewBackground() {
-    // Given
-    appBar.headerViewController.headerView.backgroundColor = UIColor.black
-
-    // When
-    mutator.mutate(appBar)
-
-    // Then
-    let fontColor =
-        appBar.navigationBar.titleTextAttributes![NSForegroundColorAttributeName] as! UIColor
-    let tintColor = appBar.navigationBar.tintColor
-    let accessibleColor = MDFTextAccessibility.textColor(onBackgroundColor: UIColor.black,
-                                                                          targetTextAlpha: 1.0,
-                                                                          font: nil)
-    XCTAssertEqual(fontColor, accessibleColor)
-    XCTAssertEqual(tintColor, accessibleColor)
-  }
-
-  func testLightHeaderViewBackground() {
-    // Given
-    appBar.headerViewController.headerView.backgroundColor = UIColor.white
-
-    // When
-    mutator.mutate(appBar)
-
-    // Then
-    let fontColor =
-        appBar.navigationBar.titleTextAttributes![NSForegroundColorAttributeName] as! UIColor
-    let tintColor = appBar.navigationBar.tintColor
-    let accessibleColor = MDFTextAccessibility.textColor(onBackgroundColor: UIColor.white,
-                                                                          targetTextAlpha: 1.0,
-                                                                          font: nil)
-    XCTAssertEqual(fontColor, accessibleColor)
-    XCTAssertEqual(tintColor, accessibleColor)
-  }
-
-  func testNoBackgroundColorSet() {
-    // Given
-    let defaultBackgroundColor = appBar.headerViewController.headerView.backgroundColor!
-
-    // When
-    mutator.mutate(appBar)
-
-    // Then
-    let fontColor =
-        appBar.navigationBar.titleTextAttributes![NSForegroundColorAttributeName] as! UIColor
-    let tintColor = appBar.navigationBar.tintColor
-    let accessibleColor = MDFTextAccessibility.textColor(onBackgroundColor: defaultBackgroundColor,
-                                                                          targetTextAlpha: 1.0,
-                                                                          font: nil)
-    XCTAssertEqual(fontColor, accessibleColor)
-    XCTAssertEqual(tintColor, accessibleColor)
-  }
-
-  func testConflictingHeaderViewNavigationBarBackgroundColors() {
-    // Given
-    appBar.headerViewController.headerView.backgroundColor = UIColor.white
-    appBar.navigationBar.backgroundColor = UIColor.black
-
-    // When
-    mutator.mutate(appBar)
-
-    // Then
-    let fontColor =
-        appBar.navigationBar.titleTextAttributes![NSForegroundColorAttributeName] as! UIColor
-    let tintColor = appBar.navigationBar.tintColor
-    let accessibleColor = MDFTextAccessibility.textColor(onBackgroundColor: UIColor.black,
-                                                                          targetTextAlpha: 1.0,
-                                                                          font: nil)
-    XCTAssertEqual(fontColor, accessibleColor)
-    XCTAssertEqual(tintColor, accessibleColor)
-  }
-
-}
diff --git a/components/BottomAppBar/src/MDCBottomAppBarView.h b/components/BottomAppBar/src/MDCBottomAppBarView.h
index f5cf33c..43dfd7e 100644
--- a/components/BottomAppBar/src/MDCBottomAppBarView.h
+++ b/components/BottomAppBar/src/MDCBottomAppBarView.h
@@ -61,6 +61,11 @@
 @property(nonatomic, strong, nonnull, readonly) MDCFloatingButton *floatingButton;
 
 /**
+ The offset from the center of the floating button to the top edge of the navigation bar
+ */
+@property(nonatomic, assign) CGFloat floatingButtonVerticalOffset;
+
+/**
  Navigation bar items that precede the floating action button. There is no limit to the number of
  buttons that can be added, but button bar width overflow is not handled.
  */
diff --git a/components/BottomAppBar/src/MDCBottomAppBarView.m b/components/BottomAppBar/src/MDCBottomAppBarView.m
index a7cc380..4ae8657 100644
--- a/components/BottomAppBar/src/MDCBottomAppBarView.m
+++ b/components/BottomAppBar/src/MDCBottomAppBarView.m
@@ -25,6 +25,7 @@
 static NSString *kMDCBottomAppBarViewAnimKeyString = @"AnimKey";
 static NSString *kMDCBottomAppBarViewPathString = @"path";
 static NSString *kMDCBottomAppBarViewPositionString = @"position";
+static const CGFloat kMDCBottomAppBarViewFloatingButtonCenterToNavigationBarTopOffset = 0.f;
 static const CGFloat kMDCBottomAppBarViewFloatingButtonElevationPrimary = 6.f;
 static const CGFloat kMDCBottomAppBarViewFloatingButtonElevationSecondary = 4.f;
 static const int kMDCButtonAnimationDuration = 200;
@@ -73,11 +74,15 @@
 
 - (void)commonMDCBottomAppBarViewInit {
   self.cutView = [[MDCBottomAppBarCutView alloc] initWithFrame:self.bounds];
+  self.floatingButtonVerticalOffset =
+      kMDCBottomAppBarViewFloatingButtonCenterToNavigationBarTopOffset;
   [self addSubview:self.cutView];
+
   self.autoresizingMask = (UIViewAutoresizingFlexibleWidth |
                            UIViewAutoresizingFlexibleLeftMargin |
                            UIViewAutoresizingFlexibleRightMargin);
   self.layoutDirection = self.mdf_effectiveUserInterfaceLayoutDirection;
+
   [self addFloatingButton];
   [self addBottomBarLayer];
   [self addNavBar];
@@ -117,52 +122,52 @@
   }
 }
 
-- (CGPoint)getFloatingButtonCenterPositionForWidth:(CGFloat)width {
+- (CGPoint)getFloatingButtonCenterPositionForAppBarWidth:(CGFloat)appBarWidth {
   CGPoint floatingButtonPoint = CGPointZero;
-  CGFloat halfDefaultDimension = CGRectGetMidX(self.floatingButton.bounds);
-  CGFloat midX = width / 2;
+  CGFloat navigationBarTopEdgeYOffset = CGRectGetMinY(self.navBar.frame);
+  CGFloat midX = appBarWidth / 2;
+
+  floatingButtonPoint.y =
+      MAX(0.0f, navigationBarTopEdgeYOffset - self.floatingButtonVerticalOffset);
   switch (self.floatingButtonPosition) {
     case MDCBottomAppBarFloatingButtonPositionLeading: {
       if (self.layoutDirection == UIUserInterfaceLayoutDirectionLeftToRight) {
-        floatingButtonPoint = CGPointMake(kMDCBottomAppBarFloatingButtonPositionX,
-                                          halfDefaultDimension);
+        floatingButtonPoint.x = kMDCBottomAppBarFloatingButtonPositionX;
       } else {
-        floatingButtonPoint = CGPointMake(width - kMDCBottomAppBarFloatingButtonPositionX,
-                                          halfDefaultDimension);
+        floatingButtonPoint.x = appBarWidth - kMDCBottomAppBarFloatingButtonPositionX;
       }
       break;
     }
     case MDCBottomAppBarFloatingButtonPositionCenter: {
-      floatingButtonPoint = CGPointMake(midX, halfDefaultDimension);
+      floatingButtonPoint.x = midX;
       break;
     }
     case MDCBottomAppBarFloatingButtonPositionTrailing: {
       if (self.layoutDirection == UIUserInterfaceLayoutDirectionLeftToRight) {
-        floatingButtonPoint = CGPointMake(width - kMDCBottomAppBarFloatingButtonPositionX,
-                                          halfDefaultDimension);
+        floatingButtonPoint.x = appBarWidth - kMDCBottomAppBarFloatingButtonPositionX;
       } else {
-        floatingButtonPoint = CGPointMake(kMDCBottomAppBarFloatingButtonPositionX,
-                                          halfDefaultDimension);
+        floatingButtonPoint.x = kMDCBottomAppBarFloatingButtonPositionX;
       }
       break;
     }
     default:
       break;
   }
+
   return floatingButtonPoint;
 }
 
 - (void)cutBottomAppBarViewAnimated:(BOOL)animated {
-  CGPathRef cutPath =
-      [self.bottomBarLayer pathWithCutFromRect:self.bounds
-                        floatingButtonPosition:self.floatingButtonPosition
-                               layoutDirection:self.layoutDirection];
+  CGPathRef pathWithCut = [self.bottomBarLayer pathFromRect:self.bounds
+                                             floatingButton:self.floatingButton
+                                         navigationBarFrame:self.navBar.frame
+                                                  shouldCut:YES];
   if (animated) {
     CABasicAnimation *pathAnimation =
         [CABasicAnimation animationWithKeyPath:kMDCBottomAppBarViewPathString];
     pathAnimation.duration = kMDCFloatingButtonExitDuration;
     pathAnimation.fromValue = (id)self.bottomBarLayer.presentationLayer.path;
-    pathAnimation.toValue = (__bridge id _Nullable)(cutPath);
+    pathAnimation.toValue = (__bridge id _Nullable)(pathWithCut);
     pathAnimation.fillMode = kCAFillModeForwards;
     pathAnimation.removedOnCompletion = NO;
     pathAnimation.delegate = self;
@@ -170,21 +175,21 @@
                      forKey:kMDCBottomAppBarViewAnimKeyString];
     [self.bottomBarLayer addAnimation:pathAnimation forKey:kMDCBottomAppBarViewPathString];
   } else {
-    self.bottomBarLayer.path = cutPath;
+    self.bottomBarLayer.path = pathWithCut;
   }
 }
 
 - (void)healBottomAppBarViewAnimated:(BOOL)animated  {
-  CGPathRef withoutCutPath =
-      [self.bottomBarLayer pathWithoutCutFromRect:self.bounds
-                           floatingButtonPosition:self.floatingButtonPosition
-                                  layoutDirection:self.layoutDirection];
+  CGPathRef pathWithoutCut = [self.bottomBarLayer pathFromRect:self.bounds
+                                                floatingButton:self.floatingButton
+                                            navigationBarFrame:self.navBar.frame
+                                                     shouldCut:NO];
   if (animated) {
     CABasicAnimation *pathAnimation =
         [CABasicAnimation animationWithKeyPath:kMDCBottomAppBarViewPathString];
     pathAnimation.duration = kMDCFloatingButtonEnterDuration;
     pathAnimation.fromValue = (id)self.bottomBarLayer.presentationLayer.path;
-    pathAnimation.toValue = (__bridge id _Nullable)(withoutCutPath);
+    pathAnimation.toValue = (__bridge id _Nullable)(pathWithoutCut);
     pathAnimation.fillMode = kCAFillModeForwards;
     pathAnimation.removedOnCompletion = NO;
     pathAnimation.delegate = self;
@@ -192,12 +197,13 @@
                      forKey:kMDCBottomAppBarViewAnimKeyString];
     [self.bottomBarLayer addAnimation:pathAnimation forKey:kMDCBottomAppBarViewPathString];
   } else {
-    self.bottomBarLayer.path = withoutCutPath;
+    self.bottomBarLayer.path = pathWithoutCut;
   }
 }
 
 - (void)moveFloatingButtonCenterAnimated:(BOOL)animated {
-  CGPoint endPoint = [self getFloatingButtonCenterPositionForWidth:CGRectGetWidth(self.bounds)];
+  CGPoint endPoint =
+      [self getFloatingButtonCenterPositionForAppBarWidth:CGRectGetWidth(self.bounds)];
   if (animated) {
     CABasicAnimation *animation =
         [CABasicAnimation animationWithKeyPath:kMDCBottomAppBarViewPositionString];
@@ -237,15 +243,15 @@
 
 - (void)layoutSubviews {
   [super layoutSubviews];
-  self.floatingButton.center =
-      [self getFloatingButtonCenterPositionForWidth:CGRectGetWidth(self.bounds)];
-  [self renderPathBasedOnFloatingButtonVisibitlityAnimated:NO];
 
-  CGRect navBarFrame = CGRectMake(0,
-                                  kMDCBottomAppBarYOffset,
-                                  CGRectGetWidth(self.bounds),
-                                  kMDCBottomAppBarHeight - kMDCBottomAppBarYOffset);
+  CGRect navBarFrame =
+      CGRectMake(0, kMDCBottomAppBarNavigationViewYOffset, CGRectGetWidth(self.bounds),
+                 kMDCBottomAppBarHeight - kMDCBottomAppBarNavigationViewYOffset);
   self.navBar.frame = navBarFrame;
+
+  self.floatingButton.center =
+      [self getFloatingButtonCenterPositionForAppBarWidth:CGRectGetWidth(self.bounds)];
+  [self renderPathBasedOnFloatingButtonVisibitlityAnimated:NO];
 }
 
 - (UIEdgeInsets)mdc_safeAreaInsets {
diff --git a/components/BottomAppBar/src/private/MDCBottomAppBarAttributes.h b/components/BottomAppBar/src/private/MDCBottomAppBarAttributes.h
index d49e8f9..b31f4a4 100644
--- a/components/BottomAppBar/src/private/MDCBottomAppBarAttributes.h
+++ b/components/BottomAppBar/src/private/MDCBottomAppBarAttributes.h
@@ -17,18 +17,15 @@
 // The height of the bottom app bar navigation area in collapsed state.
 static const CGFloat kMDCBottomAppBarHeight = 96.f;
 
-// The offset of the top of the containing view of the bottom app bar and the visible layer of the
-// bottom app bar.
-static const CGFloat kMDCBottomAppBarYOffset = 38.f;
+// The offset from the top of the navigation view of the bottom app bar to the
+// bottom app bar position
+static const CGFloat kMDCBottomAppBarNavigationViewYOffset = 38.f;
 
 // The horizontal position of the center of the floating button when in leading or trailing state.
 static const CGFloat kMDCBottomAppBarFloatingButtonPositionX = 64.f;
 
-// The vertical position of the center of the floating button.
-static const CGFloat kMDCBottomAppBarFloatingButtonPositionY = 10.f;
-
-// The radius of the path cut for the floating button.
-static const CGFloat kMDCBottomAppBarFloatingButtonRadius = 32.f;
+// The delta radius of the path cut for the floating button to the floating button's radius.
+static const CGFloat kMDCBottomAppBarFloatingButtonRadiusOffset = 4.f;
 
 // The duration of the enter animation of the path cut, same as floating button enter animation.
 static const NSTimeInterval kMDCFloatingButtonEnterDuration = 0.270f;
diff --git a/components/BottomAppBar/src/private/MDCBottomAppBarLayer.h b/components/BottomAppBar/src/private/MDCBottomAppBarLayer.h
index 44b6a5c..e0ceeeb 100644
--- a/components/BottomAppBar/src/private/MDCBottomAppBarLayer.h
+++ b/components/BottomAppBar/src/private/MDCBottomAppBarLayer.h
@@ -18,12 +18,9 @@
 
 @interface MDCBottomAppBarLayer : CAShapeLayer
 
-- (CGPathRef)pathWithCutFromRect:(CGRect)rect
-          floatingButtonPosition:(MDCBottomAppBarFloatingButtonPosition)floatingButtonPosition
-                 layoutDirection:(UIUserInterfaceLayoutDirection)layoutDirection;
-
-- (CGPathRef)pathWithoutCutFromRect:(CGRect)rect
-             floatingButtonPosition:(MDCBottomAppBarFloatingButtonPosition)floatingButtonPosition
-                    layoutDirection:(UIUserInterfaceLayoutDirection)layoutDirection;
+- (CGPathRef)pathFromRect:(CGRect)rect
+           floatingButton:(MDCFloatingButton *)floatingButton
+       navigationBarFrame:(CGRect)navigationBarFrame
+                shouldCut:(BOOL)shouldCut;
 
 @end
diff --git a/components/BottomAppBar/src/private/MDCBottomAppBarLayer.m b/components/BottomAppBar/src/private/MDCBottomAppBarLayer.m
index 90fd1b1..d9263aa 100644
--- a/components/BottomAppBar/src/private/MDCBottomAppBarLayer.m
+++ b/components/BottomAppBar/src/private/MDCBottomAppBarLayer.m
@@ -36,228 +36,81 @@
   return layer;
 }
 
-- (CGPathRef)pathWithCutFromRect:(CGRect)rect
-          floatingButtonPosition:(MDCBottomAppBarFloatingButtonPosition)floatingButtonPosition
-                 layoutDirection:(UIUserInterfaceLayoutDirection)layoutDirection {
+- (CGPathRef)pathFromRect:(CGRect)rect
+           floatingButton:(MDCFloatingButton *)floatingButton
+       navigationBarFrame:(CGRect)navigationBarFrame
+                shouldCut:(BOOL)shouldCut {
   UIBezierPath *bottomBarPath = [UIBezierPath bezierPath];
 
-  static CGFloat kStartAngle;
-  static CGFloat kEndAngle;
-  static dispatch_once_t onceToken;
-  dispatch_once(&onceToken, ^{
-    // Since we know the hypotenuse (radius) and opposite side (height above the line) we can
-    // compute the angle.
-    // sin( θ ) = opposite / hypotenuse
-    // θ = arcsin( opposite / hypotenuse )
-    // More reading: https://www.mathsisfun.com/algebra/trig-finding-angle-right-triangle.html
-    kEndAngle = (CGFloat)asin(kMDCBottomAppBarFloatingButtonPositionY /
-                              kMDCBottomAppBarFloatingButtonRadius);
-    kStartAngle = (CGFloat)(M_PI - kEndAngle);
-  });
+  CGFloat arcRadius =
+      CGRectGetHeight(floatingButton.bounds) / 2 + kMDCBottomAppBarFloatingButtonRadiusOffset;
+  CGFloat navigationBarYOffset = CGRectGetMinY(navigationBarFrame);
+  CGFloat halfAngle = acosf((float)((navigationBarYOffset - floatingButton.center.y) / arcRadius));
+  CGFloat startAngle = (float)M_PI / 2.0f + halfAngle;
+  CGFloat endAngle = (float)M_PI / 2.0f - halfAngle;
+  CGFloat halfOfHypotenuseLength = sinf((float)halfAngle) * arcRadius;
 
   CGFloat width = CGRectGetWidth(rect);
   CGFloat height = CGRectGetHeight(rect);
-  CGFloat midX = CGRectGetMidX(rect);
 
-  // Paths generated below differ based on the placement of the floating button.
-  switch (floatingButtonPosition) {
-    case MDCBottomAppBarFloatingButtonPositionLeading: {
-      if (layoutDirection == UIUserInterfaceLayoutDirectionRightToLeft) {
-        [self pathWithCutRight:bottomBarPath
-                         width:width
-                        height:height
-                    startAngle:kStartAngle
-                      endAngle:kEndAngle];
-      } else {
-        [self pathWithCutLeft:bottomBarPath
-                        width:width
-                       height:height
-                   startAngle:kStartAngle
-                     endAngle:kEndAngle];
-      }
-      break;
-    }
-    case MDCBottomAppBarFloatingButtonPositionCenter: {
-      [bottomBarPath moveToPoint:CGPointMake(0, kMDCBottomAppBarYOffset)];
-      CGPoint centerPath = CGPointMake(midX,
-                                       kMDCBottomAppBarYOffset -
-                                       kMDCBottomAppBarFloatingButtonPositionY);
-      [bottomBarPath addArcWithCenter:centerPath
-                               radius:kMDCBottomAppBarFloatingButtonRadius
-                           startAngle:kStartAngle
-                             endAngle:kEndAngle
-                            clockwise:NO];
-      [bottomBarPath addLineToPoint:CGPointMake(width, kMDCBottomAppBarYOffset)];
-      [bottomBarPath addLineToPoint:CGPointMake(width, height * 2)];
-      [bottomBarPath addLineToPoint:CGPointMake(0, height * 2)];
-      [bottomBarPath closePath];
-      break;
-    }
-    case MDCBottomAppBarFloatingButtonPositionTrailing: {
-      if (layoutDirection == UIUserInterfaceLayoutDirectionRightToLeft) {
-        [self pathWithCutLeft:bottomBarPath
-                        width:width
-                       height:height
-                   startAngle:kStartAngle
-                     endAngle:kEndAngle];
-      } else {
-        [self pathWithCutRight:bottomBarPath
-                         width:width
-                        height:height
-                    startAngle:kStartAngle
-                      endAngle:kEndAngle];
-      }
-      break;
-    }
-    default: {
-
-      // The default path does not contain a cut for the floating button. However, it is necessary
-      // to include the same number of points as the cut path version so there is a smooth
-      // transition between cut and without cut paths.
-      [bottomBarPath moveToPoint:CGPointMake(0, kMDCBottomAppBarYOffset)];
-      [bottomBarPath addLineToPoint:CGPointMake(height, kMDCBottomAppBarYOffset)];
-      [bottomBarPath addLineToPoint:CGPointMake(height,
-                                                height * 2 + kMDCBottomAppBarYOffset)];
-      [bottomBarPath addLineToPoint:CGPointMake(0, height * 2 + kMDCBottomAppBarYOffset)];
-      [bottomBarPath closePath];
-      break;
-    }
+  if (shouldCut) {
+    [self drawWithPathToCut:bottomBarPath
+                    yOffset:navigationBarYOffset
+                      width:width
+                     height:height
+                  arcCenter:floatingButton.center
+                  arcRadius:arcRadius
+                 startAngle:startAngle
+                   endAngle:endAngle];
+  } else {
+    [self drawWithPlainPath:bottomBarPath
+                    yOffset:navigationBarYOffset
+                      width:width
+                     height:height
+                  arcCenter:floatingButton.center
+           hypotenuseLength:halfOfHypotenuseLength * 2];
   }
+
   return bottomBarPath.CGPath;
 }
 
-- (UIBezierPath *)pathWithCutLeft:(UIBezierPath *)bottomBarPath
-                            width:(CGFloat)width
-                           height:(CGFloat)height
-                       startAngle:(CGFloat)startAngle
-                         endAngle:(CGFloat)endAngle {
-  [bottomBarPath moveToPoint:CGPointMake(0, kMDCBottomAppBarYOffset)];
-  CGPoint centerPath = CGPointMake(kMDCBottomAppBarFloatingButtonPositionX,
-                                   kMDCBottomAppBarYOffset -
-                                   kMDCBottomAppBarFloatingButtonPositionY);
-  [bottomBarPath addArcWithCenter:centerPath
-                           radius:kMDCBottomAppBarFloatingButtonRadius
+#pragma mark - Draw Helpers
+
+- (UIBezierPath *)drawWithPathToCut:(UIBezierPath *)bottomBarPath
+                            yOffset:(CGFloat)yOffset
+                              width:(CGFloat)width
+                             height:(CGFloat)height
+                          arcCenter:(CGPoint)arcCenter
+                          arcRadius:(CGFloat)arcRadius
+                         startAngle:(CGFloat)startAngle
+                           endAngle:(CGFloat)endAngle {
+  [bottomBarPath moveToPoint:CGPointMake(0, yOffset)];
+  [bottomBarPath addArcWithCenter:arcCenter
+                           radius:arcRadius
                        startAngle:startAngle
                          endAngle:endAngle
                         clockwise:NO];
-  [bottomBarPath addLineToPoint:CGPointMake(width, kMDCBottomAppBarYOffset)];
-  [bottomBarPath addLineToPoint:CGPointMake(width,
-                                            height * 2 + kMDCBottomAppBarYOffset)];
-  [bottomBarPath addLineToPoint:CGPointMake(0, height * 2 + kMDCBottomAppBarYOffset)];
+  [bottomBarPath addLineToPoint:CGPointMake(width, yOffset)];
+  [bottomBarPath addLineToPoint:CGPointMake(width, height * 2 + yOffset)];
+  [bottomBarPath addLineToPoint:CGPointMake(0, height * 2 + yOffset)];
   [bottomBarPath closePath];
   return bottomBarPath;
 }
 
-- (UIBezierPath *)pathWithCutRight:(UIBezierPath *)bottomBarPath
-                             width:(CGFloat)width
-                            height:(CGFloat)height
-                        startAngle:(CGFloat)startAngle
-                          endAngle:(CGFloat)endAngle {
-  [bottomBarPath moveToPoint:CGPointMake(0, kMDCBottomAppBarYOffset)];
-  CGPoint centerPath = CGPointMake(width - kMDCBottomAppBarFloatingButtonPositionX,
-                                   kMDCBottomAppBarYOffset -
-                                   kMDCBottomAppBarFloatingButtonPositionY);
-  [bottomBarPath addArcWithCenter:centerPath
-                           radius:kMDCBottomAppBarFloatingButtonRadius
-                       startAngle:startAngle
-                         endAngle:endAngle
-                        clockwise:NO];
-  [bottomBarPath addLineToPoint:CGPointMake(width, kMDCBottomAppBarYOffset)];
-  [bottomBarPath addLineToPoint:CGPointMake(width, height * 2 + kMDCBottomAppBarYOffset)];
-  [bottomBarPath addLineToPoint:CGPointMake(0, height * 2 + kMDCBottomAppBarYOffset)];
-  [bottomBarPath closePath];
-  return bottomBarPath;
-}
-
-- (CGPathRef)pathWithoutCutFromRect:(CGRect)rect
-             floatingButtonPosition:(MDCBottomAppBarFloatingButtonPosition)floatingButtonPosition
-                    layoutDirection:(UIUserInterfaceLayoutDirection)layoutDirection {
-
-  CGFloat height = CGRectGetHeight(rect);
-  CGFloat width = CGRectGetWidth(rect);
-  CGFloat midX = CGRectGetMidX(rect);
-
-  UIBezierPath *bottomBarPath = [UIBezierPath bezierPath];
-  switch (floatingButtonPosition) {
-    case MDCBottomAppBarFloatingButtonPositionLeading: {
-      if (layoutDirection == UIUserInterfaceLayoutDirectionRightToLeft) {
-        [self pathWithoutCutRight:bottomBarPath width:width height:height];
-      } else {
-        [self pathWithoutCutLeft:bottomBarPath width:width height:height];
-      }
-      break;
-    }
-    case MDCBottomAppBarFloatingButtonPositionCenter: {
-      CGFloat offsetRadiusDiff = kMDCBottomAppBarYOffset - kMDCBottomAppBarFloatingButtonRadius;
-      [bottomBarPath moveToPoint:CGPointMake(0, kMDCBottomAppBarYOffset)];
-      [bottomBarPath addLineToPoint:CGPointMake(midX - offsetRadiusDiff,
-                                                kMDCBottomAppBarYOffset)];
-      [bottomBarPath addLineToPoint:CGPointMake(midX, kMDCBottomAppBarYOffset)];
-      [bottomBarPath addLineToPoint:CGPointMake(midX + offsetRadiusDiff,
-                                                kMDCBottomAppBarYOffset)];
-      [bottomBarPath addLineToPoint:CGPointMake(width, kMDCBottomAppBarYOffset)];
-      [bottomBarPath addLineToPoint:CGPointMake(width, height * 2 + kMDCBottomAppBarYOffset)];
-      [bottomBarPath addLineToPoint:CGPointMake(0, height * 2 + kMDCBottomAppBarYOffset)];
-      [bottomBarPath closePath];
-      break;
-    }
-    case MDCBottomAppBarFloatingButtonPositionTrailing: {
-      if (layoutDirection == UIUserInterfaceLayoutDirectionRightToLeft) {
-        [self pathWithoutCutLeft:bottomBarPath width:width height:height];
-      } else {
-        [self pathWithoutCutRight:bottomBarPath width:width height:height];
-      }
-      break;
-    }
-    default: {
-      [bottomBarPath moveToPoint:CGPointMake(0, kMDCBottomAppBarYOffset)];
-      [bottomBarPath addLineToPoint:CGPointMake(height, kMDCBottomAppBarYOffset)];
-      [bottomBarPath addLineToPoint:CGPointMake(height,
-                                                height * 2 + kMDCBottomAppBarYOffset)];
-      [bottomBarPath addLineToPoint:CGPointMake(0, height * 2 + kMDCBottomAppBarYOffset)];
-      [bottomBarPath closePath];
-      break;
-    }
-  }
-  return bottomBarPath.CGPath;
-}
-
-- (UIBezierPath *)pathWithoutCutLeft:(UIBezierPath *)bottomBarPath
-                               width:(CGFloat)width
-                              height:(CGFloat)height {
-  CGFloat offsetRadiusDiff = kMDCBottomAppBarYOffset - kMDCBottomAppBarFloatingButtonRadius;
-  [bottomBarPath moveToPoint:CGPointMake(0, kMDCBottomAppBarYOffset)];
-  [bottomBarPath addLineToPoint:CGPointMake(kMDCBottomAppBarFloatingButtonPositionX -
-                                            offsetRadiusDiff,
-                                            kMDCBottomAppBarYOffset)];
-  [bottomBarPath addLineToPoint:CGPointMake(kMDCBottomAppBarFloatingButtonPositionX,
-                                            kMDCBottomAppBarYOffset)];
-  [bottomBarPath addLineToPoint:CGPointMake(kMDCBottomAppBarFloatingButtonPositionX +
-                                            offsetRadiusDiff,
-                                            kMDCBottomAppBarYOffset)];
-  [bottomBarPath addLineToPoint:CGPointMake(width, kMDCBottomAppBarYOffset)];
-  [bottomBarPath addLineToPoint:CGPointMake(width, height * 2 + kMDCBottomAppBarYOffset)];
-  [bottomBarPath addLineToPoint:CGPointMake(0, height * 2 + kMDCBottomAppBarYOffset)];
-  [bottomBarPath closePath];
-  return bottomBarPath;
-}
-
-- (UIBezierPath *)pathWithoutCutRight:(UIBezierPath *)bottomBarPath
-                                width:(CGFloat)width
-                               height:(CGFloat)height {
-  CGFloat offsetRadiusDiff = kMDCBottomAppBarYOffset - kMDCBottomAppBarFloatingButtonRadius;
-  [bottomBarPath moveToPoint:CGPointMake(0, kMDCBottomAppBarYOffset)];
-  [bottomBarPath addLineToPoint:CGPointMake(width - kMDCBottomAppBarFloatingButtonPositionX -
-                                            offsetRadiusDiff,
-                                            kMDCBottomAppBarYOffset)];
-  [bottomBarPath addLineToPoint:CGPointMake(width - kMDCBottomAppBarFloatingButtonPositionX,
-                                            kMDCBottomAppBarYOffset)];
-  [bottomBarPath addLineToPoint:CGPointMake(width - kMDCBottomAppBarFloatingButtonPositionX +
-                                            offsetRadiusDiff,
-                                            kMDCBottomAppBarYOffset)];
-  [bottomBarPath addLineToPoint:CGPointMake(width, kMDCBottomAppBarYOffset)];
-  [bottomBarPath addLineToPoint:CGPointMake(width, height * 2 + kMDCBottomAppBarYOffset)];
-  [bottomBarPath addLineToPoint:CGPointMake(0, height * 2 + kMDCBottomAppBarYOffset)];
+- (UIBezierPath *)drawWithPlainPath:(UIBezierPath *)bottomBarPath
+                            yOffset:(CGFloat)yOffset
+                              width:(CGFloat)width
+                             height:(CGFloat)height
+                          arcCenter:(CGPoint)arcCenter
+                   hypotenuseLength:(CGFloat)hypotenuseLength {
+  CGFloat halfOfHypotenuseLength = hypotenuseLength / 2;
+  [bottomBarPath moveToPoint:CGPointMake(0, yOffset)];
+  [bottomBarPath addLineToPoint:CGPointMake(arcCenter.x - halfOfHypotenuseLength, yOffset)];
+  [bottomBarPath addLineToPoint:CGPointMake(arcCenter.x, yOffset)];
+  [bottomBarPath addLineToPoint:CGPointMake(arcCenter.x + halfOfHypotenuseLength, yOffset)];
+  [bottomBarPath addLineToPoint:CGPointMake(width, yOffset)];
+  [bottomBarPath addLineToPoint:CGPointMake(width, height * 2 + yOffset)];
+  [bottomBarPath addLineToPoint:CGPointMake(0, height * 2 + yOffset)];
   [bottomBarPath closePath];
   return bottomBarPath;
 }
diff --git a/components/BottomAppBar/tests/unit/BottomAppBarTests.m b/components/BottomAppBar/tests/unit/BottomAppBarTests.m
index ebfff66..d7072d6 100644
--- a/components/BottomAppBar/tests/unit/BottomAppBarTests.m
+++ b/components/BottomAppBar/tests/unit/BottomAppBarTests.m
@@ -61,4 +61,16 @@
   XCTAssertEqualObjects(self.bottomAppBar.navBar.trailingBarItemsTintColor, UIColor.purpleColor);
 }
 
+#pragma mark - Floating Button
+
+- (void)testCustomizedFloatingButtonVerticalHeight {
+  CGFloat veriticalOffset = 5.0f;
+  self.bottomAppBar.floatingButtonVerticalOffset = veriticalOffset;
+  [self.bottomAppBar layoutSubviews];
+  CGPoint floatingButtonPosition = self.bottomAppBar.floatingButton.center;
+  CGPoint navigationBarPosition = self.bottomAppBar.navBar.frame.origin;
+  XCTAssertEqualWithAccuracy(floatingButtonPosition.y + veriticalOffset, navigationBarPosition.y,
+                             0.001f);
+}
+
 @end
diff --git a/components/Dialogs/examples/AlertComparison.swift b/components/Dialogs/examples/AlertComparison.swift
index df8ece4..6f8d0a5 100644
--- a/components/Dialogs/examples/AlertComparison.swift
+++ b/components/Dialogs/examples/AlertComparison.swift
@@ -14,15 +14,21 @@
 
 import Foundation
 import MaterialComponents.MaterialButtons
+import MaterialComponents.MaterialColorScheme
 import MaterialComponents.MaterialDialogs
-
+import MaterialComponents.MaterialDialogs_DialogThemer
+import MaterialComponents.MaterialTypographyScheme
 
 /// This interface allows a user to present a UIKit Alert Controller and a Material Alert
 /// Controller.
 class DialogsAlertComparison: UIViewController {
 
-  let materialButton = MDCFlatButton()
-  let uikitButton = MDCFlatButton()
+  var colorScheme = MDCSemanticColorScheme()
+  var typographyScheme = MDCTypographyScheme()
+
+  private let materialButton = MDCFlatButton()
+  private let themedButton = MDCFlatButton()
+  private let uikitButton = MDCFlatButton()
 
   override func viewDidLoad() {
     super.viewDidLoad()
@@ -38,21 +44,44 @@
 
     NSLayoutConstraint.activate([
       NSLayoutConstraint(item:materialButton,
-                       attribute:.centerX,
-                       relatedBy:.equal,
-                       toItem:self.view,
-                       attribute:.centerX,
-                       multiplier:1.0,
+                       attribute: .centerX,
+                       relatedBy: .equal,
+                       toItem: self.view,
+                       attribute: .centerX,
+                       multiplier: 1.0,
                        constant: 0.0),
-      NSLayoutConstraint(item:materialButton,
-                       attribute:.centerY,
-                       relatedBy:.equal,
-                       toItem:self.view,
-                       attribute:.centerY,
-                       multiplier:1.0,
+      NSLayoutConstraint(item: materialButton,
+                       attribute: .centerY,
+                       relatedBy: .equal,
+                       toItem: self.view,
+                       attribute: .centerY,
+                       multiplier: 1.0,
                        constant: 0.0)
       ])
 
+    themedButton.translatesAutoresizingMaskIntoConstraints = false
+    themedButton.setTitle("Material Alert (Themed)", for: .normal)
+    themedButton.setTitleColor(UIColor(white: 0.1, alpha:1), for: .normal)
+    themedButton.sizeToFit()
+    themedButton.addTarget(self, action: #selector(tapThemed), for: .touchUpInside)
+    self.view.addSubview(themedButton)
+
+    NSLayoutConstraint.activate([
+      NSLayoutConstraint(item: themedButton,
+                         attribute: .centerX,
+                         relatedBy: .equal,
+                         toItem: self.view,
+                         attribute: .centerX,
+                         multiplier: 1.0,
+                         constant: 0.0),
+      NSLayoutConstraint(item:themedButton,
+                         attribute: .top,
+                         relatedBy: .equal,
+                         toItem: materialButton,
+                         attribute: .bottom,
+                         multiplier: 1.0,
+                         constant: 8.0)
+      ])
 
       uikitButton.translatesAutoresizingMaskIntoConstraints = false
       uikitButton.setTitle("UIKit Alert", for: UIControlState())
@@ -62,26 +91,48 @@
       self.view.addSubview(uikitButton)
 
       NSLayoutConstraint.activate([
-        NSLayoutConstraint(item:uikitButton,
-                           attribute:.centerX,
-                           relatedBy:.equal,
-                           toItem:self.view,
-                           attribute:.centerX,
-                           multiplier:1.0,
+        NSLayoutConstraint(item: uikitButton,
+                           attribute: .centerX,
+                           relatedBy: .equal,
+                           toItem: self.view,
+                           attribute: .centerX,
+                           multiplier: 1.0,
                            constant: 0.0),
-        NSLayoutConstraint(item:uikitButton,
-                           attribute:.top,
-                           relatedBy:.equal,
-                           toItem:materialButton,
-                           attribute:.bottom,
-                           multiplier:1.0,
+        NSLayoutConstraint(item: uikitButton,
+                           attribute: .top,
+                           relatedBy: .equal,
+                           toItem: themedButton,
+                           attribute: .bottom,
+                           multiplier: 1.0,
                            constant: 8.0)
         ])
   }
 
   @objc func tapMaterial(_ sender: Any) {
-    let titleString = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur"
-    let messageString = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur " +
+    let alertController = createMDCAlertController()
+    self.present(alertController, animated: true, completion: nil)
+  }
+
+  @objc func tapThemed(_ sender: Any) {
+
+    let alertController = createMDCAlertController()
+
+    let scheme = MDCAlertScheme()
+    scheme.colorScheme = self.colorScheme
+    scheme.typographyScheme = self.typographyScheme
+
+    MDCAlertControllerThemer.applyScheme(scheme, to: alertController)
+    self.present(alertController, animated: true, completion: nil)
+  }
+
+  @objc func tapUIKit(_ sender: Any) {
+    let alertController = createUIAlertController()
+    self.present(alertController, animated: true, completion: nil)
+  }
+
+  private var titleAndMessage: (title: String, message: String) {
+    return (title: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur",
+            message: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur " +
       "ultricies diam libero, eget porta arcu feugiat sit amet. Maecenas placerat felis sed risus " +
       "maximus tempus. Integer feugiat, augue in pellentesque dictum, justo erat ultricies leo, " +
       "quis eleifend nisi eros dictum mi. In finibus vulputate eros, in luctus diam auctor in. " +
@@ -100,8 +151,13 @@
       "ultricies diam libero, eget porta arcu feugiat sit amet. Maecenas placerat felis sed risus " +
       "maximus tempus. Integer feugiat, augue in pellentesque dictum, justo erat ultricies leo, " +
       "quis eleifend nisi eros dictum mi. In finibus vulputate eros, in luctus diam auctor in. "
+    )
+  }
 
-    let alertController = MDCAlertController(title: titleString, message: messageString)
+  private func createMDCAlertController() -> MDCAlertController {
+
+    let texts = titleAndMessage
+    let alertController = MDCAlertController(title: texts.title, message: texts.message)
 
     let acceptAction = MDCAlertAction(title:"Accept") { (_) in print("Accept") }
     alertController.addAction(acceptAction)
@@ -112,33 +168,13 @@
     let rejectAction = MDCAlertAction(title:"Reject") { (_) in print("Reject") }
     alertController.addAction(rejectAction)
 
-    self.present(alertController, animated: true, completion: nil)
+    return alertController
   }
 
-  @objc func tapUIKit(_ sender: Any) {
-    let titleString = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur"
-    let messageString = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur " +
-      "ultricies diam libero, eget porta arcu feugiat sit amet. Maecenas placerat felis sed risus " +
-      "maximus tempus. Integer feugiat, augue in pellentesque dictum, justo erat ultricies leo, " +
-      "quis eleifend nisi eros dictum mi. In finibus vulputate eros, in luctus diam auctor in. " +
-      "ultricies diam libero, eget porta arcu feugiat sit amet. Maecenas placerat felis sed risus " +
-      "maximus tempus. Integer feugiat, augue in pellentesque dictum, justo erat ultricies leo, " +
-      "quis eleifend nisi eros dictum mi. In finibus vulputate eros, in luctus diam auctor in. " +
-      "ultricies diam libero, eget porta arcu feugiat sit amet. Maecenas placerat felis sed risus " +
-      "maximus tempus. Integer feugiat, augue in pellentesque dictum, justo erat ultricies leo, " +
-      "quis eleifend nisi eros dictum mi. In finibus vulputate eros, in luctus diam auctor in. " +
-      "ultricies diam libero, eget porta arcu feugiat sit amet. Maecenas placerat felis sed risus " +
-      "maximus tempus. Integer feugiat, augue in pellentesque dictum, justo erat ultricies leo, " +
-      "quis eleifend nisi eros dictum mi. In finibus vulputate eros, in luctus diam auctor in. " +
-      "ultricies diam libero, eget porta arcu feugiat sit amet. Maecenas placerat felis sed risus " +
-      "maximus tempus. Integer feugiat, augue in pellentesque dictum, justo erat ultricies leo, " +
-      "quis eleifend nisi eros dictum mi. In finibus vulputate eros, in luctus diam auctor in. " +
-      "ultricies diam libero, eget porta arcu feugiat sit amet. Maecenas placerat felis sed risus " +
-      "maximus tempus. Integer feugiat, augue in pellentesque dictum, justo erat ultricies leo, " +
-      "quis eleifend nisi eros dictum mi. In finibus vulputate eros, in luctus diam auctor in. "
+  private func createUIAlertController() -> UIAlertController {
 
-    let alertController = UIAlertController(title: titleString,
-                                            message: messageString,
+    let texts = titleAndMessage
+    let alertController = UIAlertController(title: texts.title, message: texts.message,
                                             preferredStyle:.alert)
 
     let acceptAction = UIAlertAction(title:"Accept", style:.default) { (_) in print("Accept") }
@@ -151,7 +187,7 @@
     let rejectAction = UIAlertAction(title:"Reject", style:.default) { (_) in print("Reject") }
     alertController.addAction(rejectAction)
 
-    self.present(alertController, animated: true, completion: nil)
+    return alertController
   }
 }
 
diff --git a/components/Dialogs/examples/DialogsAlertCustomizationViewController.swift b/components/Dialogs/examples/DialogsAlertCustomizationViewController.swift
new file mode 100644
index 0000000..13931cc
--- /dev/null
+++ b/components/Dialogs/examples/DialogsAlertCustomizationViewController.swift
@@ -0,0 +1,147 @@
+// Copyright 2018-present the Material Components for iOS authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import Foundation
+import MaterialComponents.MaterialButtons
+import MaterialComponents.MaterialColorScheme
+import MaterialComponents.MaterialDialogs
+import MaterialComponents.MaterialCollections
+import MaterialComponents.MaterialDialogs_DialogThemer
+import MaterialComponents.MaterialTypographyScheme
+
+class CustomAlertViewController: UIViewController {
+
+  let bodyLabel = UILabel()
+  let dismissButton = MDCFlatButton()
+
+  var cornerRadius: CGFloat {
+    set { view.layer.cornerRadius = newValue }
+    get { return view.layer.cornerRadius }
+  }
+
+  override var preferredContentSize: CGSize {
+    get { return CGSize(width:200.0, height:140.0); }
+    set { super.preferredContentSize = newValue }
+  }
+
+  override func viewDidLoad() {
+
+    super.viewDidLoad()
+    view.backgroundColor = UIColor.white
+
+    bodyLabel.text = "This is a view controller."
+    bodyLabel.translatesAutoresizingMaskIntoConstraints = false
+    bodyLabel.numberOfLines = 0
+    bodyLabel.sizeToFit()
+    self.view.addSubview(bodyLabel)
+
+    NSLayoutConstraint.activate(
+      NSLayoutConstraint.constraints(withVisualFormat: "H:|-[body]-|", options: [],
+                                     metrics: nil, views: ["body": bodyLabel]))
+    NSLayoutConstraint.activate(
+      NSLayoutConstraint.constraints(withVisualFormat: "V:|-[body]-|", options: [],
+                                     metrics: nil, views: ["body": bodyLabel]))
+  }
+}
+
+class DialogsAlertCustomizationViewController: MDCCollectionViewController {
+
+  var colorScheme = MDCSemanticColorScheme()
+  var typographyScheme = MDCTypographyScheme()
+  var alertScheme: MDCAlertScheme {
+    let scheme = MDCAlertScheme()
+    scheme.colorScheme = self.colorScheme
+    scheme.typographyScheme = self.typographyScheme
+    return scheme
+  }
+
+  let kReusableIdentifierItem = "customCell"
+
+  var menu: [String] = []
+
+  override func viewDidLoad() {
+    super.viewDidLoad()
+
+    view.backgroundColor = UIColor.white
+
+    loadCollectionView(menu: ["Dialog with Centered Title"])
+  }
+
+  func loadCollectionView(menu: [String]) {
+    self.collectionView?.register(MDCCollectionViewTextCell.self, forCellWithReuseIdentifier: kReusableIdentifierItem)
+    self.menu = menu
+  }
+
+  override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
+    switch indexPath.row {
+    case 0:
+      didTapCenteredTitle()
+    default:
+      print("No row is selected")
+    }
+  }
+
+  func didTapCenteredTitle() {
+    let alert = createMDCAlertController(title: "Dialog Title")
+    alert.titleAlignment = .center // todo: theme with themer when available
+    MDCAlertControllerThemer.applyScheme(alertScheme, to: alert)
+    self.present(alert, animated: true, completion: nil)
+  }
+
+  private func createMDCAlertController(title: String) -> MDCAlertController {
+    let alertController = MDCAlertController(title: title, message: """
+      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+      tempor incididunt ut labore et dolore magna aliqua.
+      """)
+    alertController.addAction(MDCAlertAction(title:"OK") { _ in print("OK") })
+    alertController.addAction(MDCAlertAction(title:"Cancel") { _ in print("Cancel") })
+    return alertController
+  }
+
+}
+
+// MDCCollectionViewController Data Source
+extension DialogsAlertCustomizationViewController {
+
+  override func numberOfSections(in collectionView: UICollectionView) -> Int {
+    return 1
+  }
+
+  override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
+    return menu.count
+  }
+
+  override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
+
+    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: kReusableIdentifierItem,
+                                                  for: indexPath)
+    guard let customCell = cell as? MDCCollectionViewTextCell else { return cell }
+
+    customCell.textLabel?.text = menu[indexPath.row]
+
+    return customCell
+  }
+}
+
+// MARK: Catalog by convention
+extension DialogsAlertCustomizationViewController {
+
+  class func catalogMetadata() -> [String: Any] {
+    return [
+      "breadcrumbs": ["Dialogs", "Alert Customization"],
+      "primaryDemo": false,
+      "presentable": false,
+    ]
+  }
+}
diff --git a/components/Dialogs/examples/DialogsAlertViewController.m b/components/Dialogs/examples/DialogsAlertViewController.m
index 08393d5..39d824f 100644
--- a/components/Dialogs/examples/DialogsAlertViewController.m
+++ b/components/Dialogs/examples/DialogsAlertViewController.m
@@ -12,11 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#import "supplemental/DialogsAlertViewControllerSupplemental.h"
+#import "MaterialDialogs+DialogThemer.h"
 #import "MaterialButtons.h"
 #import "MaterialDialogs.h"
-#import "MaterialDialogs+ColorThemer.h"
-#import "MaterialDialogs+TypographyThemer.h"
+#import "supplemental/DialogsAlertViewControllerSupplemental.h"
 
 @implementation DialogsAlertViewController
 
@@ -70,9 +69,10 @@
 }
 
 - (void)themeAlertController:(MDCAlertController *)alertController {
-  [MDCAlertColorThemer applySemanticColorScheme:self.colorScheme toAlertController:alertController];
-  [MDCAlertTypographyThemer applyTypographyScheme:self.typographyScheme
-                                toAlertController:alertController];
+  MDCAlertScheme *alertScheme = [[MDCAlertScheme alloc] init];
+  alertScheme.colorScheme = self.colorScheme;
+  alertScheme.typographyScheme = self.typographyScheme;
+  [MDCAlertControllerThemer applyScheme:alertScheme toAlertController:alertController];
 }
 
 - (IBAction)didTapShowAlert {
@@ -366,7 +366,6 @@
 
   MDCAlertController *materialAlertController =
       [MDCAlertController alertControllerWithTitle:titleString message:messageString];
-  [self themeAlertController:materialAlertController];
 
   MDCAlertAction *agreeAaction = [MDCAlertAction actionWithTitle:@"AGREE"
                                                          handler:^(MDCAlertAction *action) {
diff --git a/components/Dialogs/examples/DialogsRoundedCornerViewController.m b/components/Dialogs/examples/DialogsRoundedCornerViewController.m
index 1fa0944..aa796be 100644
--- a/components/Dialogs/examples/DialogsRoundedCornerViewController.m
+++ b/components/Dialogs/examples/DialogsRoundedCornerViewController.m
@@ -42,8 +42,6 @@
            forControlEvents:UIControlEventTouchUpInside];
 
   [self.view addSubview:_dismissButton];
-
-  self.view.layer.cornerRadius = 24.0;
 }
 
 - (void)viewWillLayoutSubviews {
@@ -105,12 +103,19 @@
 }
 
 - (IBAction)didTapPresent:(id)sender {
-  UIViewController *viewController =
+  DialogsRoundedCornerSimpleController *viewController =
       [[DialogsRoundedCornerSimpleController alloc] initWithNibName:nil bundle:nil];
 
   viewController.modalPresentationStyle = UIModalPresentationCustom;
   viewController.transitioningDelegate = self.transitionController;
 
+  // sets the dialog's corner radius
+  viewController.view.layer.cornerRadius = 24.0f;
+
+  // ensure shadow/tracking layer matches the dialog's corner radius
+  MDCDialogPresentationController *controller = viewController.mdc_dialogPresentationController;
+  controller.dialogCornerRadius = viewController.view.layer.cornerRadius;
+
   [self presentViewController:viewController animated:YES completion:NULL];
 }
 
diff --git a/components/Dialogs/src/DialogThemer/MDCAlertControllerThemer.h b/components/Dialogs/src/DialogThemer/MDCAlertControllerThemer.h
index e3a0f76e..1302207 100644
--- a/components/Dialogs/src/DialogThemer/MDCAlertControllerThemer.h
+++ b/components/Dialogs/src/DialogThemer/MDCAlertControllerThemer.h
@@ -14,7 +14,7 @@
 
 #import <Foundation/Foundation.h>
 
-#import "MDCAlertController.h"
+#import "MaterialDialogs.h"
 #import "MDCAlertScheme.h"
 
 @interface MDCAlertControllerThemer : NSObject
diff --git a/components/Dialogs/src/MDCAlertController.h b/components/Dialogs/src/MDCAlertController.h
index 994a8f3..332277a 100644
--- a/components/Dialogs/src/MDCAlertController.h
+++ b/components/Dialogs/src/MDCAlertController.h
@@ -73,6 +73,9 @@
 /** The color applied to the title of Alert Controller.*/
 @property(nonatomic, strong, nullable) UIColor *titleColor;
 
+/** The alignment applied to the title of the Alert Controller.*/
+@property(nonatomic, assign) NSTextAlignment titleAlignment;
+
 /** The font applied to the message of Alert Controller.*/
 @property(nonatomic, strong, nullable) UIFont *messageFont;
 
diff --git a/components/Dialogs/src/MDCAlertController.m b/components/Dialogs/src/MDCAlertController.m
index faa2184..1eb0820 100644
--- a/components/Dialogs/src/MDCAlertController.m
+++ b/components/Dialogs/src/MDCAlertController.m
@@ -212,13 +212,24 @@
   }
 }
 
+- (void)setTitleAlignment:(NSTextAlignment)titleAlignment {
+  _titleAlignment = titleAlignment;
+  if (self.alertView) {
+    self.alertView.titleAlignment = titleAlignment;
+  }
+}
+
 - (void)setCornerRadius:(CGFloat)cornerRadius {
   _cornerRadius = cornerRadius;
-  self.alertView.cornerRadius = cornerRadius;
+  if (self.alertView) {
+    self.alertView.cornerRadius = cornerRadius;
+  }
   // make sure to pass the new shape through to the dialog's tracking/shadow layer
   MDCDialogPresentationController *dialogPresentationController =
       self.mdc_dialogPresentationController;
-  dialogPresentationController.dialogCornerRadius = cornerRadius;
+  if (dialogPresentationController) {
+    dialogPresentationController.dialogCornerRadius = cornerRadius;
+  }
 }
 
 - (void)mdc_setAdjustsFontForContentSizeCategory:(BOOL)adjusts {
@@ -317,6 +328,7 @@
   self.alertView.buttonColor = self.buttonTitleColor;
   self.alertView.buttonFont = self.buttonFont;
   self.alertView.buttonInkColor = self.buttonInkColor;
+  self.alertView.titleAlignment = self.titleAlignment;
   self.alertView.cornerRadius = self.cornerRadius;
 
   for (MDCAlertAction *action in self.actions) {
diff --git a/components/Dialogs/src/MDCAlertControllerView.h b/components/Dialogs/src/MDCAlertControllerView.h
index 093b7ed..2234c4a 100644
--- a/components/Dialogs/src/MDCAlertControllerView.h
+++ b/components/Dialogs/src/MDCAlertControllerView.h
@@ -19,6 +19,8 @@
 @property(nonatomic, strong, nullable) UIFont *titleFont UI_APPEARANCE_SELECTOR;
 @property(nonatomic, strong, nullable) UIColor *titleColor UI_APPEARANCE_SELECTOR;
 
+@property(nonatomic, assign) NSTextAlignment titleAlignment;
+
 @property(nonatomic, strong, nullable) UIFont *messageFont UI_APPEARANCE_SELECTOR;
 @property(nonatomic, strong, nullable) UIColor *messageColor UI_APPEARANCE_SELECTOR;
 
diff --git a/components/Dialogs/src/private/MDCAlertControllerView+Private.m b/components/Dialogs/src/private/MDCAlertControllerView+Private.m
index 75651fc..0612137 100644
--- a/components/Dialogs/src/private/MDCAlertControllerView+Private.m
+++ b/components/Dialogs/src/private/MDCAlertControllerView+Private.m
@@ -52,6 +52,8 @@
     BOOL _mdc_adjustsFontForContentSizeCategory;
 }
 
+@dynamic titleAlignment;
+
 - (instancetype)initWithFrame:(CGRect)frame {
   self = [super initWithFrame:frame];
   if (self) {
@@ -171,6 +173,14 @@
   _titleLabel.textColor = titleColor;
 }
 
+- (NSTextAlignment)titleAlignment {
+  return self.titleLabel.textAlignment;
+}
+
+- (void)setTitleAlignment:(NSTextAlignment)titleAlignment {
+  self.titleLabel.textAlignment = titleAlignment;
+}
+
 - (NSString *)message {
   return self.messageLabel.text;
 }
diff --git a/components/Dialogs/tests/unit/MDCAlertControllerCustomizationTests.m b/components/Dialogs/tests/unit/MDCAlertControllerCustomizationTests.m
new file mode 100644
index 0000000..9f6434a
--- /dev/null
+++ b/components/Dialogs/tests/unit/MDCAlertControllerCustomizationTests.m
@@ -0,0 +1,51 @@
+// Copyright 2018-present the Material Components for iOS authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#import "MaterialDialogs+TypographyThemer.h"
+#import "MaterialDialogs.h"
+
+#import "MDCAlertControllerView+Private.h"
+
+#import <XCTest/XCTest.h>
+
+@interface MDCAlertControllerCustomizationTests : XCTestCase
+
+@end
+
+@implementation MDCAlertControllerCustomizationTests
+
+- (void)setUp {
+  [super setUp];
+}
+
+- (void)tearDown {
+  [super tearDown];
+}
+
+- (void)testApplyingTitleAlignment {
+  // Given
+  MDCAlertController *alert = [MDCAlertController alertControllerWithTitle:@"Title"
+                                                                   message:@"Message"];
+  MDCAlertControllerView *alertView = (MDCAlertControllerView *)alert.view;
+  NSTextAlignment titleAlignment = NSTextAlignmentCenter;
+
+  // When
+  alert.titleAlignment = titleAlignment;
+
+  // Then
+  XCTAssertEqual(alertView.titleAlignment, titleAlignment);
+  XCTAssertEqual(alertView.titleLabel.textAlignment, titleAlignment);
+}
+
+@end
diff --git a/components/FlexibleHeader/src/MDCFlexibleHeaderView.m b/components/FlexibleHeader/src/MDCFlexibleHeaderView.m
index d6e2fe3..9d7149a 100644
--- a/components/FlexibleHeader/src/MDCFlexibleHeaderView.m
+++ b/components/FlexibleHeader/src/MDCFlexibleHeaderView.m
@@ -101,6 +101,13 @@
 // The amount injected into scrollIndicatorInsets.top
 @property(nonatomic) CGFloat injectedTopScrollIndicatorInset;
 
+// When working with multiple tracking scroll views, this property keeps track of what the last
+// header height for a given tracking scroll view was. When we return to a tracking scroll view,
+// we're able to use this property to calculate any additional content offset shift that may be
+// required in order to maintain a consistent physical placement within the content.
+@property(nonatomic) CGFloat stashedHeight;
+@property(nonatomic) BOOL stashedHeightIsValid;
+
 @end
 
 @implementation MDCFlexibleHeaderView {
@@ -1308,6 +1315,41 @@
 }
 #endif
 
+#pragma mark Multiple tracking scroll views
+
+// Given a tracking scroll view and a potential new tracking scroll view, updates the state of the
+// header and scroll view such that header's height will not change once the scroll view becomes the
+// new tracking scroll view.
+- (void)fhv_matchHeightWithScrollView:(UIScrollView *)scrollView {
+  if (self.trackingScrollView == nil) {
+    return;
+  }
+
+  MDCFlexibleHeaderScrollViewInfo *info = [_trackedScrollViews objectForKey:scrollView];
+
+  if (_shiftAccumulator >= [self fhv_accumulatorMax]) {
+    // We're shifted off-screen, make sure that this scroll view isn't expecting to show the header.
+
+    CGPoint offset = scrollView.contentOffset;
+    CGFloat rawTopInset = scrollView.contentInset.top - info.injectedTopContentInset;
+    if (offset.y < -rawTopInset) {
+      offset.y = -rawTopInset;
+      scrollView.contentOffset = offset;
+    }
+  }
+
+  if (info.stashedHeightIsValid) {
+    // Did our height change since the last time we saw this content?
+    const CGFloat heightDelta = self.bounds.size.height - info.stashedHeight;
+    if (fabs(heightDelta) > DBL_EPSILON) {
+      // Offset our content accordingly so that we're still viewing what we were viewing last time.
+      CGPoint offset = scrollView.contentOffset;
+      offset.y -= heightDelta;
+      scrollView.contentOffset = offset;
+    }
+  }
+}
+
 #pragma mark - MDCStatusBarShifterDelegate
 
 - (void)statusBarShifterNeedsStatusBarAppearanceUpdate:
@@ -1360,6 +1402,11 @@
 
   UIScrollView *oldTrackingScrollView = _trackingScrollView;
 
+  if (_trackingInfo != nil) {
+    _trackingInfo.stashedHeight = self.bounds.size.height;
+    _trackingInfo.stashedHeightIsValid = YES;
+  }
+
   BOOL wasTrackingScrollView = _trackingScrollView != nil;
   _trackingScrollView = trackingScrollView;
 
@@ -1374,6 +1421,8 @@
   _shiftAccumulatorDeltaY = 0;
 
   _trackingInfo = [_trackedScrollViews objectForKey:_trackingScrollView];
+  _trackingInfo.stashedHeightIsValid = NO;
+  _trackingInfo.stashedHeight = 0;
 
   [self fhv_enforceInsetsForScrollView:_trackingScrollView];
 
@@ -1381,6 +1430,32 @@
     [self fhv_startObservingContentOffset];
   }
 
+  // When canAlwaysExpandToMaximumHeight is enabled our header's height no longer directly
+  // correlates to the content offset - it's also augmented by the shift accumulator. In order to
+  // keep the header's height constant when changing the tracking scroll view, we need to adjust
+  // the shift accumulator accordingly.
+  if (self.canAlwaysExpandToMaximumHeight && self.sharedWithManyScrollViews &&
+      wasTrackingScrollView) {
+    // What's our expected height now that we've changed the tracking scroll view?
+    CGFloat headerHeight = -[self fhv_contentOffsetWithoutInjectedTopInset];
+    headerHeight = MAX(self.computedMinimumHeight, MIN(self.computedMaximumHeight, headerHeight));
+
+    // How much will our height change if we do nothing right now?
+    const CGFloat heightDelta = self.bounds.size.height - headerHeight;
+
+    // Cap the accumulator to ensure it's valid.
+    CGFloat accumulatorMin;
+    if (headerHeight > self.computedMinimumHeight + DBL_EPSILON) {
+      // We're attached to the content, so don't allow any height accumulation.
+      accumulatorMin = 0;
+    } else {
+      accumulatorMin = [self fhv_accumulatorMin];
+    }
+    // Adjust the accumulator so that our height won't change and cap it to the possible range.
+    _shiftAccumulator =
+        MAX(accumulatorMin, MIN([self fhv_accumulatorMax], _shiftAccumulator - heightDelta));
+  }
+
   void (^animate)(void) = ^{
     [self fhv_updateLayout];
   };
@@ -1727,36 +1802,7 @@
     scrollView.contentOffset = offset;
   }
 
-  if (self.trackingScrollView == nil) {
-    return;
-  }
-
-  if (_shiftAccumulator >= [self fhv_accumulatorMax]) {
-    // We're shifted off-screen, make sure that this scroll view isn't expecting to show the header.
-
-    CGPoint offset = scrollView.contentOffset;
-    CGFloat rawTopInset = scrollView.contentInset.top - info.injectedTopContentInset;
-    if (offset.y < -rawTopInset) {
-      offset.y = -rawTopInset;
-      scrollView.contentOffset = offset;
-    }
-
-  } else if (self.trackingScrollView.contentOffset.y != scrollView.contentOffset.y &&
-             self.trackingScrollView.contentOffset.y <= 0 && scrollView.contentOffset.y <= 0) {
-    // Our content is expanding the header in both columns, let's match up the content offsets so
-    // that the header's height won't change.
-    CGPoint offset = scrollView.contentOffset;
-    offset.y = self.trackingScrollView.contentOffset.y;
-    scrollView.contentOffset = offset;
-
-  } else if (self.trackingScrollView.contentOffset.y > scrollView.contentOffset.y
-             && scrollView.contentOffset.y < 0) { // Destination is showing an expanded header.
-    // Our header is possibly smaller now than it will be when we move to the new content.
-    // Scroll the new content such that we collapse the header to the current height.
-    CGPoint offset = scrollView.contentOffset;
-    offset.y = MIN(self.trackingScrollView.contentOffset.y, 0);
-    scrollView.contentOffset = offset;
-  }
+  [self fhv_matchHeightWithScrollView:scrollView];
 }
 
 - (void)shiftHeaderOnScreenAnimated:(BOOL)animated {
diff --git a/components/FlexibleHeader/tests/unit/FlexibleHeaderTopSafeAreaTests.m b/components/FlexibleHeader/tests/unit/FlexibleHeaderTopSafeAreaTests.m
index d65ceca..8790e31 100644
--- a/components/FlexibleHeader/tests/unit/FlexibleHeaderTopSafeAreaTests.m
+++ b/components/FlexibleHeader/tests/unit/FlexibleHeaderTopSafeAreaTests.m
@@ -18,20 +18,12 @@
 
 #import "MaterialFlexibleHeader.h"
 
-#import "../../src/private/MDCFlexibleHeaderTopSafeArea.h"
-
+#import "supplemental/FlexibleHeaderTopSafeAreaTestsFakeTopSafeAreaDelegate.h"
 #import "supplemental/FlexibleHeaderTopSafeAreaTestsFakeViewController.h"
 
 @interface FlexibleHeaderTopSafeAreaTests : XCTestCase
 @end
 
-@interface FlexibleHeaderTopSafeAreaTestsFakeTopSafeAreaDelegate
-    : NSObject <MDCFlexibleHeaderSafeAreaDelegate>
-@property(nonatomic) BOOL isStatusBarShifted;
-@property(nonatomic) BOOL topSafeAreaInsetDidChangeWasCalled;
-@property(nonatomic) CGFloat deviceTopSafeAreaInset;
-@end
-
 @implementation FlexibleHeaderTopSafeAreaTests {
   MDCFlexibleHeaderTopSafeArea *_topSafeArea;
   FlexibleHeaderTopSafeAreaTestsFakeTopSafeAreaDelegate *_delegate;
@@ -225,23 +217,3 @@
 }
 
 @end
-
-#pragma mark - Fake implementations
-
-@implementation FlexibleHeaderTopSafeAreaTestsFakeTopSafeAreaDelegate
-
-#pragma mark MDCFlexibleHeaderTopSafeAreaDelegate
-
-- (BOOL)flexibleHeaderSafeAreaIsStatusBarShifted:(MDCFlexibleHeaderTopSafeArea *)safeAreas {
-  return self.isStatusBarShifted;
-}
-
-- (void)flexibleHeaderSafeAreaTopSafeAreaInsetDidChange:(MDCFlexibleHeaderTopSafeArea *)safeAreas {
-  self.topSafeAreaInsetDidChangeWasCalled = YES;
-}
-
-- (CGFloat)flexibleHeaderSafeAreaDeviceTopSafeAreaInset:(MDCFlexibleHeaderTopSafeArea *)safeAreas {
-  return self.deviceTopSafeAreaInset;
-}
-
-@end
diff --git a/components/FlexibleHeader/tests/unit/supplemental/FlexibleHeaderTopSafeAreaTestsFakeTopSafeAreaDelegate.h b/components/FlexibleHeader/tests/unit/supplemental/FlexibleHeaderTopSafeAreaTestsFakeTopSafeAreaDelegate.h
new file mode 100644
index 0000000..735a3c7
--- /dev/null
+++ b/components/FlexibleHeader/tests/unit/supplemental/FlexibleHeaderTopSafeAreaTestsFakeTopSafeAreaDelegate.h
@@ -0,0 +1,24 @@
+// Copyright 2018-present the Material Components for iOS authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#import <Foundation/Foundation.h>
+
+#import "../../../src/private/MDCFlexibleHeaderTopSafeArea.h"
+
+@interface FlexibleHeaderTopSafeAreaTestsFakeTopSafeAreaDelegate
+    : NSObject <MDCFlexibleHeaderSafeAreaDelegate>
+@property(nonatomic) BOOL isStatusBarShifted;
+@property(nonatomic) BOOL topSafeAreaInsetDidChangeWasCalled;
+@property(nonatomic) CGFloat deviceTopSafeAreaInset;
+@end
diff --git a/components/FlexibleHeader/tests/unit/supplemental/FlexibleHeaderTopSafeAreaTestsFakeTopSafeAreaDelegate.m b/components/FlexibleHeader/tests/unit/supplemental/FlexibleHeaderTopSafeAreaTestsFakeTopSafeAreaDelegate.m
new file mode 100644
index 0000000..d705fd2
--- /dev/null
+++ b/components/FlexibleHeader/tests/unit/supplemental/FlexibleHeaderTopSafeAreaTestsFakeTopSafeAreaDelegate.m
@@ -0,0 +1,33 @@
+// Copyright 2018-present the Material Components for iOS authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#import "FlexibleHeaderTopSafeAreaTestsFakeTopSafeAreaDelegate.h"
+
+@implementation FlexibleHeaderTopSafeAreaTestsFakeTopSafeAreaDelegate
+
+#pragma mark MDCFlexibleHeaderTopSafeAreaDelegate
+
+- (BOOL)flexibleHeaderSafeAreaIsStatusBarShifted:(MDCFlexibleHeaderTopSafeArea *)safeAreas {
+  return self.isStatusBarShifted;
+}
+
+- (void)flexibleHeaderSafeAreaTopSafeAreaInsetDidChange:(MDCFlexibleHeaderTopSafeArea *)safeAreas {
+  self.topSafeAreaInsetDidChangeWasCalled = YES;
+}
+
+- (CGFloat)flexibleHeaderSafeAreaDeviceTopSafeAreaInset:(MDCFlexibleHeaderTopSafeArea *)safeAreas {
+  return self.deviceTopSafeAreaInset;
+}
+
+@end
diff --git a/components/LibraryInfo/src/MDCLibraryInfo.m b/components/LibraryInfo/src/MDCLibraryInfo.m
index 75fa37b..456ab9e 100644
--- a/components/LibraryInfo/src/MDCLibraryInfo.m
+++ b/components/LibraryInfo/src/MDCLibraryInfo.m
@@ -19,7 +19,7 @@
 // This string is updated automatically as a part of the release process and should not be edited
 // manually. Do not rename this constant or change the formatting without updating the release
 // scripts.
-static NSString const *MDCLibraryInfoVersionString = @"64.0.0";
+static NSString const *MDCLibraryInfoVersionString = @"65.0.0";
 
 @implementation MDCLibraryInfo
 
diff --git a/components/LibraryInfo/tests/unit/LibraryInfoTests.swift b/components/LibraryInfo/tests/unit/LibraryInfoTests.swift
index 97417dd..215695c 100644
--- a/components/LibraryInfo/tests/unit/LibraryInfoTests.swift
+++ b/components/LibraryInfo/tests/unit/LibraryInfoTests.swift
@@ -21,7 +21,7 @@
     // Given
 
     // This regex pattern does the following:
-    // Accept: "64.0.0", etc.
+    // Accept: "65.0.0", etc.
     // Reject: "0.0.0", "1.2", "1", "-1.2.3", "Hi, I'm a version 1.2.3", "1.2.3 is my version", etc.
     //
     // Note the major version must be >= 1 since "0.0.0" is used as the version when something goes
diff --git a/components/NavigationDrawer/src/private/MDCBottomDrawerContainerViewController.m b/components/NavigationDrawer/src/private/MDCBottomDrawerContainerViewController.m
index d9a7e67..07123dd 100644
--- a/components/NavigationDrawer/src/private/MDCBottomDrawerContainerViewController.m
+++ b/components/NavigationDrawer/src/private/MDCBottomDrawerContainerViewController.m
@@ -207,12 +207,6 @@
                             self.presentingViewBounds.size.height + headerHeightWithoutInset;
   BOOL scrollingUpInFull = contentDiff < 0 && self.trackingScrollView.bounds.origin.y > 0;
   if (self.scrollView.bounds.origin.y >= drawerOffset || scrollingUpInFull) {
-    // Update the main content view's scrollView offset
-    CGRect contentViewBounds = self.trackingScrollView.bounds;
-    contentViewBounds.origin.y += contentDiff;
-    contentViewBounds.origin.y = MIN(maxScrollOrigin, MAX(contentViewBounds.origin.y, 0));
-    self.trackingScrollView.bounds = contentViewBounds;
-
     // If we reach full screen or if we are scrolling up after being in full screen.
     if (self.trackingScrollView.bounds.origin.y < maxScrollOrigin || scrollingUpInFull) {
       // If we still didn't reach the end of the content, or if we are scrolling up after reaching
@@ -227,13 +221,21 @@
       CGSize scrollViewContentSize = self.presentingViewBounds.size;
       scrollViewContentSize.height += self.contentHeightSurplus;
       self.scrollView.contentSize = scrollViewContentSize;
+
+      // Update the main content view's scrollView offset
+      CGRect contentViewBounds = self.trackingScrollView.bounds;
+      contentViewBounds.origin.y += contentDiff;
+      contentViewBounds.origin.y = MIN(maxScrollOrigin, MAX(contentViewBounds.origin.y, 0));
+      self.trackingScrollView.bounds = contentViewBounds;
     } else {
-      // Have the drawer's scrollView's content size be static so it will bounce when reaching the
-      // end of the content.
-      CGSize scrollViewContentSize = self.scrollView.contentSize;
-      scrollViewContentSize.height =
-          drawerOffset + self.scrollView.frame.size.height + 2 * topAreaInsetForHeader;
-      self.scrollView.contentSize = scrollViewContentSize;
+      if (self.trackingScrollView.contentSize.height >= self.trackingScrollView.frame.size.height) {
+        // Have the drawer's scrollView's content size be static so it will bounce when reaching the
+        // end of the content.
+        CGSize scrollViewContentSize = self.scrollView.contentSize;
+        scrollViewContentSize.height =
+            drawerOffset + self.scrollView.frame.size.height + 2 * topAreaInsetForHeader;
+        self.scrollView.contentSize = scrollViewContentSize;
+      }
     }
   }
 }
diff --git a/components/ShadowLayer/examples/ShadowCornerRadiusExample.m b/components/ShadowLayer/examples/ShadowCornerRadiusExample.m
index f23263f..e2284e0 100644
--- a/components/ShadowLayer/examples/ShadowCornerRadiusExample.m
+++ b/components/ShadowLayer/examples/ShadowCornerRadiusExample.m
@@ -96,6 +96,7 @@
 
 - (void)viewDidLoad {
   [super viewDidLoad];
+
   self.view.backgroundColor = [UIColor whiteColor];
   self.title = @"Shadow Corner Radius";
   _shadowsView = [[ShadowCornerRadiusView alloc] initWithFrame:self.view.bounds];
@@ -104,6 +105,19 @@
   [self.view addSubview:_shadowsView];
 }
 
+- (void)viewDidLayoutSubviews {
+  [super viewDidLayoutSubviews];
+
+  if (@available(iOS 11.0, *)) {
+    _shadowsView.frame = UIEdgeInsetsInsetRect(self.view.bounds, self.view.safeAreaInsets);
+  } else {
+    CGRect frame = self.view.bounds;
+    frame.origin.y += self.topLayoutGuide.length;
+    frame.size.height -= self.topLayoutGuide.length;
+    _shadowsView.frame = frame;
+  }
+}
+
 #pragma mark catalog by convention
 
 + (NSDictionary *)catalogMetadata {
diff --git a/components/Snackbar/src/MDCSnackbarManager.h b/components/Snackbar/src/MDCSnackbarManager.h
index 597db73..ab7baf5 100644
--- a/components/Snackbar/src/MDCSnackbarManager.h
+++ b/components/Snackbar/src/MDCSnackbarManager.h
@@ -221,6 +221,12 @@
 @property(nonatomic, readwrite, setter=mdc_setAdjustsFontForContentSizeCategory:)
     BOOL mdc_adjustsFontForContentSizeCategory;
 
+/**
+ If enabled, accessibilityViewIsModal will be enabled for all non-transient snackbar views.
+
+ Default is set to NO.
+ */
+@property(nonatomic, assign) BOOL shouldEnableAccessibilityViewIsModal;
 
 /**
  The delegate for MDCSnackbarManager through which it may inform of snackbar presentation updates.
diff --git a/components/Snackbar/src/MDCSnackbarManager.m b/components/Snackbar/src/MDCSnackbarManager.m
index 115ff1a..ed6f2c4 100644
--- a/components/Snackbar/src/MDCSnackbarManager.m
+++ b/components/Snackbar/src/MDCSnackbarManager.m
@@ -13,10 +13,13 @@
 // limitations under the License.
 
 #import "MDCSnackbarManager.h"
+
 #import "MDCSnackbarMessage.h"
 #import "MDCSnackbarMessageView.h"
-#import "MaterialOverlayWindow.h"
 #import "MaterialApplication.h"
+#import "MaterialOverlayWindow.h"
+
+#import "private/MDCSnackbarManagerInternal.h"
 #import "private/MDCSnackbarMessageInternal.h"
 #import "private/MDCSnackbarMessageViewInternal.h"
 #import "private/MDCSnackbarOverlayView.h"
@@ -42,7 +45,14 @@
 /**
  The 'actual' Snackbar manager which will take care of showing/hiding Snackbar messages.
  */
-@interface MDCSnackbarManagerInternal : NSObject
+@interface MDCSnackbarManagerInternal ()
+
+/**
+ This property is used to test logic flows only when voiceover is on.
+
+ Note: we can't fake or mock the system calls like UIAccessibilityIsVoiceOverRunning()
+ */
+@property(nonatomic) BOOL isVoiceOverRunningOverride;
 
 /**
  The instance of MDCSnackbarManager that "owns" this internal manager.  Used to get theming
@@ -220,6 +230,8 @@
                                     snackbarManager:self.manager];
   [self.delegate willPresentSnackbarWithMessageView:snackbarView];
   self.currentSnackbar = snackbarView;
+  self.overlayView.accessibilityViewIsModal =
+      self.manager.shouldEnableAccessibilityViewIsModal && ![self isSnackbarTransient:snackbarView];
   self.overlayView.hidden = NO;
   [self activateOverlay:self.overlayView];
 
@@ -299,8 +311,16 @@
 
 #pragma mark - Helper methods
 
+- (BOOL)isVoiceOverRunning {
+  if (UIAccessibilityIsVoiceOverRunning() || UIAccessibilityIsSwitchControlRunning() ||
+      self.isVoiceOverRunningOverride) {
+    return YES;
+  }
+  return NO;
+}
+
 - (BOOL)isSnackbarTransient:(MDCSnackbarMessageView *)snackbarView {
-  if (UIAccessibilityIsVoiceOverRunning() || UIAccessibilityIsSwitchControlRunning()) {
+  if ([self isVoiceOverRunning]) {
     return ![snackbarView shouldWaitForDismissalDuringVoiceover];
   }
 
diff --git a/components/Snackbar/src/private/MDCSnackbarManagerInternal.h b/components/Snackbar/src/private/MDCSnackbarManagerInternal.h
new file mode 100644
index 0000000..08c99ea
--- /dev/null
+++ b/components/Snackbar/src/private/MDCSnackbarManagerInternal.h
@@ -0,0 +1,19 @@
+// Copyright 2016-present the Material Components for iOS authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/**
+ The 'actual' Snackbar manager which will take care of showing/hiding Snackbar messages.
+ */
+@interface MDCSnackbarManagerInternal : NSObject
+@end
diff --git a/components/Snackbar/tests/unit/MDCSnackbarMessageViewTests.m b/components/Snackbar/tests/unit/MDCSnackbarMessageViewTests.m
index d47f969..2c0778d 100644
--- a/components/Snackbar/tests/unit/MDCSnackbarMessageViewTests.m
+++ b/components/Snackbar/tests/unit/MDCSnackbarMessageViewTests.m
@@ -17,6 +17,16 @@
 #import "MaterialSnackbar.h"
 #import "supplemental/MDCFakeMDCSnackbarManagerDelegate.h"
 
+#import "../../src/private/MDCSnackbarManagerInternal.h"
+#import "../../src/private/MDCSnackbarOverlayView.h"
+
+@interface MDCSnackbarManagerInternal (Testing)
+@property(nonatomic) MDCSnackbarOverlayView *overlayView;
+@property(nonatomic) BOOL isVoiceOverRunningOverride;
+@end
+@interface MDCSnackbarManager (Testing)
+@property(nonnull, nonatomic, strong) MDCSnackbarManagerInternal *internalManager;
+@end
 @interface MDCSnackbarMessageView (Testing)
 @property(nonatomic, strong) UILabel *label;
 @end
@@ -91,4 +101,60 @@
                         self.message.accessibilityHint);
 }
 
+- (void)testSnackbarSetAccessibiltyViewIsModalForActionSnacbars {
+  // Given
+  self.manager.internalManager.isVoiceOverRunningOverride = YES;
+  MDCSnackbarMessageAction *action = [[MDCSnackbarMessageAction alloc] init];
+  action.title = @"Tap Me";
+  self.message.action = action;
+  self.manager.shouldEnableAccessibilityViewIsModal = YES;
+
+  // When
+  [self.manager showMessage:self.message];
+  [NSRunLoop.mainRunLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
+
+  // Then
+  XCTAssertTrue(self.manager.internalManager.overlayView.accessibilityViewIsModal);
+}
+
+- (void)testSnackbarAccessibiltyViewIsModalShouldBeNoWithNoActions {
+  // Given
+  self.manager.shouldEnableAccessibilityViewIsModal = YES;
+
+  // When
+  [self.manager showMessage:self.message];
+  [NSRunLoop.mainRunLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
+
+  // Then
+  XCTAssertFalse(self.manager.internalManager.overlayView.accessibilityViewIsModal);
+}
+
+- (void)testSnackbarSetAccessibiltyViewIsModalShouldBeNoForActionSnacbarsWhenManagerIsNo {
+  // Given
+  self.manager.internalManager.isVoiceOverRunningOverride = YES;
+  MDCSnackbarMessageAction *action = [[MDCSnackbarMessageAction alloc] init];
+  action.title = @"Tap Me";
+  self.message.action = action;
+  self.manager.shouldEnableAccessibilityViewIsModal = NO;
+
+  // When
+  [self.manager showMessage:self.message];
+  [NSRunLoop.mainRunLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
+
+  // Then
+  XCTAssertFalse(self.manager.internalManager.overlayView.accessibilityViewIsModal);
+}
+
+- (void)testSnackbarAccessibiltyViewIsModalShouldBeNoByDefault {
+  // Given
+  self.manager.shouldEnableAccessibilityViewIsModal = NO;
+
+  // When
+  [self.manager showMessage:self.message];
+  [NSRunLoop.mainRunLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
+
+  // Then
+  XCTAssertFalse(self.manager.internalManager.overlayView.accessibilityViewIsModal);
+}
+
 @end
diff --git a/components/TextFields/examples/TextFieldKitchenSinkExample.swift b/components/TextFields/examples/TextFieldKitchenSinkExample.swift
index f518199..f09e932 100644
--- a/components/TextFields/examples/TextFieldKitchenSinkExample.swift
+++ b/components/TextFields/examples/TextFieldKitchenSinkExample.swift
@@ -202,7 +202,7 @@
     baselineTestLabel.font = textFieldFloatingCharMax.font
     self.scrollView.addSubview(baselineTestLabel)
 
-    if #available(iOSApplicationExtension 9.0, *), #available(iOS 9.0, *) {
+    if #available(iOS 9.0, *) {
       baselineTestLabel.trailingAnchor.constraint(equalTo: textFieldFloatingCharMax.trailingAnchor,
                                                  constant: 0).isActive = true
 
diff --git a/contributing/README.md b/contributing/README.md
index be63256..03e1250 100644
--- a/contributing/README.md
+++ b/contributing/README.md
@@ -34,6 +34,17 @@
 [FooBar] Removes the deprecated fooWithBar:(Bar*)bar method.
 ```
 
+### Pull request continuous integration for new contributors
+
+Continuous integration will only be initiated automatically for the [core team](https://github.com/orgs/material-components/teams/core-ios-team/members)
+and [recognized collaborators](https://github.com/orgs/material-components/teams/recognized-ios-collaborators/members).
+
+All other pull requests must be labeled with `kokoro:force-run` by a member of the repo
+with write access in order for continuous integration to be initiated. This label must
+be added again each time the pull request has new commits pushed to it.
+
+For Googlers: [b/115490922](http://b/115490922) is tracking making the above work more streamlined for new contributors.
+
 #### Using assignee to indicate who should action on a PR
 
 Since PRs on github permanently stay in the `Changes requested` state it is hard to tell when the author has addressed the concerns. By change the assignee to whomever still needs to action (review or modify/justify) we can more easily keep track of what needs attention in our PR queues.
diff --git a/contributing/releasing.md b/contributing/releasing.md
index dcbd64d..fab332d 100644
--- a/contributing/releasing.md
+++ b/contributing/releasing.md
@@ -43,12 +43,25 @@
 Our entire release process is encoded into the `release` script in the scripts/ directory.
 Read the [tool's readme](../scripts/README-release.md) to learn more about the tool.
 
-### Cut a release branch and notify clients
+### Cut a release branch and create a pull request
 
 Run the following command to cut a release:
 
     scripts/release cut
 
+Note: if for some reason `cut` fails, first ensure that nobody else is in the middle of cutting a release by visiting the repo and verifying that a release-candidate does not already exist because aborting the release will delete the remote release candidate. If that isn't the case, then please run `scripts/release abort` and try again.
+
+You will now have a local `release-candidate` branch, a new section in CHANGELOG.md titled
+"release-candidate", and the `release-candidate` branch will have been pushed to GitHub.
+
+At this point you should also create the initial Release Candidate pull request using the URL
+that the `cut` script generated.
+
+Name the Pull Request title "[WIP] Release Candidate." until you are able to provide the version as the title.
+
+**Do not use GitHub's big green button to merge the approved pull request.** Release are an
+exception to our normal squash-and-merge procedure.
+
 #### Hotfixing
 
 If you need to cut a hotfix release, run the following command instead:
@@ -64,19 +77,6 @@
 
 Other than the steps above regarding hotfixing, the entire release process stays the same.
 
-Note: if for some reason `cut` fails, first ensure that nobody else is in the middle of cutting a release by visiting the repo and verifying that a release-candidate does not already exist because aborting the release will delete the remote release candidate. If that isn't the case, then please run `scripts/release abort` and try again.
-
-You will now have a local `release-candidate` branch, a new section in CHANGELOG.md titled
-"release-candidate", and the `release-candidate` branch will have been pushed to GitHub.
-
-At this point you should also create the initial Release Candidate pull request using the URL
-that the `cut` script generated.
-
-Name the Pull Request title "[WIP] Release Candidate." until you are able to provide the version as the title.
-
-**Do not use GitHub's big green button to merge the approved pull request.** Release are an
-exception to our normal squash-and-merge procedure.
-
 ### Start internal testing
 
 You can now start the internal release testing process documented at [go/mdc-releasing](http://go/mdc-releasing).
@@ -156,7 +156,7 @@
 
 The final sanity check is to visually inspect the diff.
 
-> If you have configured Git with a GUI diff tool (`git difftool`), then you can add
+> If you have configured Git with a GUI diff tool (`git difftool`) like [Kaleidoscope](https://itunes.apple.com/us/app/kaleidoscope/id587512244?mt=12), then you can add
 > `--use_diff_tool` to `scripts/release diff` below.
 
 Generate a list of component public header changes:
diff --git a/contributing/tools.md b/contributing/tools.md
index 26fb640..e1a68d2 100644
--- a/contributing/tools.md
+++ b/contributing/tools.md
@@ -2,6 +2,18 @@
 
 ## Automatically format your Git commit with clang-format
 
+### Run
+
+To run the command use
+
+```bash
+git clang-format $(git merge-base origin/develop HEAD)
+```
+
+This diffs from origin/develop to HEAD:
+
+
+### Install
 This tool allows you to run clang-format on your local changes before they're sent out for review.
 This will minimize the amount of style feedback you get from the team and saves everyone time.
 
@@ -33,12 +45,6 @@
 git clang-format -h
 ```
 
-To run the command from origin/develop to HEAD:
-
-```bash
-git clang-format origin/develop
-```
-
 ## PR description chrome plugin
 
 https://github.com/material-foundation/github-squash-and-merge-pr-descriptions.
diff --git a/demos/supplemental/RemoteImageServiceForMDCDemos.podspec b/demos/supplemental/RemoteImageServiceForMDCDemos.podspec
index 36104db..2202833 100644
--- a/demos/supplemental/RemoteImageServiceForMDCDemos.podspec
+++ b/demos/supplemental/RemoteImageServiceForMDCDemos.podspec
@@ -1,6 +1,6 @@
 Pod::Spec.new do |s|
   s.name         = "RemoteImageServiceForMDCDemos"
-  s.version      = "64.0.0"
+  s.version      = "65.0.0"
   s.summary      = "A helper image class for the MDC demos."
   s.description  = "This spec is made for use in the MDC demos. It gets images via url."
   s.homepage     = "https://github.com/material-components/material-components-ios"
diff --git a/scripts/release b/scripts/release
index b01e5fc..89baeef 100755
--- a/scripts/release
+++ b/scripts/release
@@ -482,7 +482,11 @@
       echo >> $ALL_CHANGELOG_PATH
       echo "### $component" >> $ALL_CHANGELOG_PATH
       echo >> $ALL_CHANGELOG_PATH
-      echo "**New component.**" >> $ALL_CHANGELOG_PATH
+      if [[ "$component" = *"+"* ]]; then
+        echo "**New extension.**" >> $ALL_CHANGELOG_PATH
+      else
+        echo "**New component.**" >> $ALL_CHANGELOG_PATH
+      fi
 
       echo "New!"
       continue