diff --git a/src/material/sort/BUILD.bazel b/src/material/sort/BUILD.bazel
index 733c0754d389..4c8322720cf1 100644
--- a/src/material/sort/BUILD.bazel
+++ b/src/material/sort/BUILD.bazel
@@ -19,6 +19,7 @@ ng_module(
assets = [":sort-header.css"] + glob(["**/*.html"]),
module_name = "@angular/material/sort",
deps = [
+ "//src/cdk/a11y",
"//src/cdk/coercion",
"//src/material/core",
"@npm//@angular/animations",
diff --git a/src/material/sort/sort-header.html b/src/material/sort/sort-header.html
index 99457b14c087..96bc176f8fb8 100644
--- a/src/material/sort/sort-header.html
+++ b/src/material/sort/sort-header.html
@@ -3,9 +3,7 @@
[class.mat-sort-header-position-before]="arrowPosition == 'before'">
diff --git a/src/material/sort/sort-header.scss b/src/material/sort/sort-header.scss
index 20e630322a9a..70ad3f7a36ee 100644
--- a/src/material/sort/sort-header.scss
+++ b/src/material/sort/sort-header.scss
@@ -32,6 +32,13 @@ $mat-sort-header-arrow-hint-opacity: 0.38;
font: inherit;
color: currentColor;
+ // Usually we could rely on the arrow showing up to be focus indication, but if a header is
+ // active, the arrow will always be shown so the user has no way of telling the difference.
+ [mat-sort-header].cdk-keyboard-focused &,
+ [mat-sort-header].cdk-program-focused & {
+ border-bottom: solid 1px currentColor;
+ }
+
// The `outline: 0` from above works on all browsers, however Firefox also
// adds a special `focus-inner` which we have to disable explicitly. See:
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#Firefox
diff --git a/src/material/sort/sort-header.ts b/src/material/sort/sort-header.ts
index d0ac8db4cafa..72b2357be57a 100644
--- a/src/material/sort/sort-header.ts
+++ b/src/material/sort/sort-header.ts
@@ -17,8 +17,10 @@ import {
Optional,
ViewEncapsulation,
Inject,
+ ElementRef,
} from '@angular/core';
import {CanDisable, CanDisableCtor, mixinDisabled} from '@angular/material/core';
+import {FocusMonitor} from '@angular/cdk/a11y';
import {merge, Subscription} from 'rxjs';
import {MatSort, MatSortable} from './sort';
import {matSortAnimations} from './sort-animations';
@@ -138,7 +140,13 @@ export class MatSortHeader extends _MatSortHeaderMixinBase
changeDetectorRef: ChangeDetectorRef,
@Optional() public _sort: MatSort,
@Inject('MAT_SORT_HEADER_COLUMN_DEF') @Optional()
- public _columnDef: MatSortHeaderColumnDef) {
+ public _columnDef: MatSortHeaderColumnDef,
+ /**
+ * @deprecated _focusMonitor and _elementRef to become required parameters.
+ * @breaking-change 10.0.0
+ */
+ private _focusMonitor?: FocusMonitor,
+ private _elementRef?: ElementRef) {
// Note that we use a string token for the `_columnDef`, because the value is provided both by
// `material/table` and `cdk/table` and we can't have the CDK depending on Material,
// and we want to avoid having the sort header depending on the CDK table because
@@ -163,6 +171,13 @@ export class MatSortHeader extends _MatSortHeaderMixinBase
changeDetectorRef.markForCheck();
});
+
+ if (_focusMonitor && _elementRef) {
+ // We use the focus monitor because we also want to style
+ // things differently based on the focus origin.
+ _focusMonitor.monitor(_elementRef, true)
+ .subscribe(origin => this._setIndicatorHintVisible(!!origin));
+ }
}
ngOnInit() {
@@ -179,6 +194,11 @@ export class MatSortHeader extends _MatSortHeaderMixinBase
}
ngOnDestroy() {
+ // @breaking-change 10.0.0 Remove null check for _focusMonitor and _elementRef.
+ if (this._focusMonitor && this._elementRef) {
+ this._focusMonitor.stopMonitoring(this._elementRef);
+ }
+
this._sort.deregister(this);
this._rerenderSubscription.unsubscribe();
}
diff --git a/tools/public_api_guard/material/sort.d.ts b/tools/public_api_guard/material/sort.d.ts
index 0a333793816d..24b5dfde271d 100644
--- a/tools/public_api_guard/material/sort.d.ts
+++ b/tools/public_api_guard/material/sort.d.ts
@@ -61,7 +61,8 @@ export declare class MatSortHeader extends _MatSortHeaderMixinBase implements Ca
disableClear: boolean;
id: string;
start: 'asc' | 'desc';
- constructor(_intl: MatSortHeaderIntl, changeDetectorRef: ChangeDetectorRef, _sort: MatSort, _columnDef: MatSortHeaderColumnDef);
+ constructor(_intl: MatSortHeaderIntl, changeDetectorRef: ChangeDetectorRef, _sort: MatSort, _columnDef: MatSortHeaderColumnDef,
+ _focusMonitor?: FocusMonitor | undefined, _elementRef?: ElementRef | undefined);
_getAriaSortAttribute(): "ascending" | "descending" | null;
_getArrowDirectionState(): string;
_getArrowViewState(): string;