Open byanofsky opened 3 years ago
The MatTabGroup
component encapsulates both the tab header and tab body. Observe that the tab group template is composed of two components: MatTabHeader and MatTabBody. Both of these components are private to the Angular Material library. Specifically, they are not exported in the tabs module. Therefore, there is no mechanism to consume and render these parts. Even if they were exposed, the MatTabGroup component contains logic required for operation of the tabs (I’ll refer to as tab group logic). This tab group logic includes inputs/outputs (public API), managing state, generating common unique ids for attributes, and handling tab selection. This is non-trivial logic that would need to be reproduced by the consumer.
Create two new components: MatTabGroupHeader
and MatTabGroupBody
. Each will encapsulate the header and body subcomponents of the MatTabGroup
.
MatTabGroupHeader
will also contain much of the logic that exists within MatTabGroup
that cannot be moved to one of the subcomponents. This includes such logic as managing selected tab state and managing MatTab
content children.
The MatTabGroupHeader
has a body
input that accepts a reference to a MatTabGroupBody
instance. With this reference, MatTabGroupHeader
initializes the MatTabGroupBody
with all necessary information to render content associated with the MatTabGroupHeader
's tabs.
Usage example:
<mat-tab-group-header [body]="#Body">
<mat-tab label="Tab 1">Content 1</mat-tab>
<mat-tab label="Tab 2">Content 2</mat-tab>
<mat-tab label="Tab 3">Content 3</mat-tab>
</mat-tab-group-header>
<mat-tab-group-body #body></mat-tab-group-body>
See WIP Pull Request for more details: https://github.com/angular/components/pull/23405
MatTabGroup
is composed of MatTabHeader
and MatTabBody
. Currently, both of these subcomponents are internal. If these subcomponents are exported for public consumption, a consumer can construct a component that allows rendering header and body in independent locations.
Pros:
MatTabGroup
Instead of exporting the private subcomponents, create two new components that wrap the private subcomponents.
Any MatTabGroup
logic that is specific to one of these components can be extracted into the new component. MatTabGroup
can be refactored to be a composition of these two subcomponents.
Consumers of these subcomponents will be responsible for implementing some fo the logic that exists in MatTabGroup
, but unlike option 1, the logic will be limited to that which connects the subcomponents.
Usage example:
// component.html
<mat-tab-group-header #tabHeader
[tabs]="_tabs"
[groupId]="_groupId"
(selectedIndexChange)="handleSelectedIndexChange($event)"
[disableRipple]="disableRipple">
</mat-tab-group-header>
<mat-tab-group-body #tabBodyContent
[tabs]="_tabs"
[selectedIndex]="selectedIndex"
[animationMode]="_animationMode">
</mat-tab-group-body>
// component.ts
@ContentChildren(MatTab) _tabs = new QueryList<MatTab>;
@ViewChild('tabHeader') _tabHeader;
@ViewChild('tabBody') _tabBody;
@Input() selectedIndex = 0;
private _groupId = ++nextId;
handleSelectedIndexChange(index: number) {
/* … */
}
Pros:
MatTabGroupHeader
and MatTabGroupBody
componentsLike the recommended solution, create two new components: MatTabGroupHeader
and MatTabGroupBody
. Unlike the recommended solution, MatTabGroupHeader
will not handle connecting the MatTabGroupBody
. Instead, the consumer will be responsible for connecting the components in the template.
Usage example:
<mat-tab-group-header #tabGroupHeader
[disablePagination]="true">
<mat-tab label="First">Content 1</mat-tab>
<mat-tab label="Second">Content 2</mat-tab>
<mat-tab label="Third">Content 3</mat-tab>
</mat-tab-group-header>
<mat-tab-group-body [tabs]="tabGroupHeader.tabs"
[groupId]="tabGroupHeader.groupId"
[selectedIndex$]="tabGroupHeader.selectedIndexObs"
animationDuration="1000ms">
</mat-tab-group-body>
Pros:
MatTabGroup
with optional body
inputCreate a new MatTabGroupBody
component. But instead of creating a new MatTabGroupHeader
, update the existing MatTabGroup
. Add an optional body
input to the component that accepts a MatTabGroupBody
reference.
When a body reference is passed, MatTabGroup
will render tab content to the MatTabGroupBody
instead of to its internally defined body.
Pros:
MatTabGroup
Cons:MatTabGroup
with two code paths: 1. render internal tab body, 2. render external tab bodyMatTabGroupHeader & MatTabGroupBody
Updating design based on discussions with @andrewseguin.
2 new components will be extracted from MatTabGroup
. They are MatTabList
and MatTabPanel
(to match naming of the ARIA pattern).
Both components will be mostly stateless. For example, MatTabList
the currently selected tab will be determined by the selectedIndex
input. When a tab is clicked, the index of the clicked tab will emit via the selectedIndexChange
output. But selected index state will not be stored within the MatTabList
.
MatTabGroup
will be refactored as a composition of these two components.
Finally, for consumers who desire rendering tab list and tab panel independently, we'll provide a service that will manage syncing state between the tab list and tab panel (as the MatTabGroup
component currently does).
Intentionally excludes the sync service (details of which are TBD).
<mat-tab-list>
<mat-tab-list-label> Tab 1 </mat-tab-list-label>
<mat-tab-list-label> Tab 2 </mat-tab-list-label>
<mat-tab-list-label> Tab 2 </mat-tab-list-label>
</mat-tab-list>
<mat-tab-panel>
<mat-tab-panel-content> Tab 1 Content </mat-tab-panel-content>
<mat-tab-panel-content> Tab 2 Content </mat-tab-panel-content>
<mat-tab-panel-content> Tab 3 Content </mat-tab-panel-content>
</mat-tab-panel>
Just a heads up that we kicked off a community voting process for your feature request. There are 20 days until the voting process ends.
Find more details about Angular's feature request process in our documentation.
Thank you for submitting your feature request! Looks like during the polling process it didn't collect a sufficient number of votes to move to the next stage.
We want to keep Angular rich and ergonomic and at the same time be mindful about its scope and learning journey. If you think your request could live outside Angular's scope, we'd encourage you to collaborate with the community on publishing it as an open source package.
You can find more details about the feature request process in our documentation.
Any updates on this?
Feature Description
Currently,
MatTabGroup
renders the tab content immediately below the list of tab labels:This new feature will enable consumers to specify a separate location where the tab content should be rendered.
Use Case
The goal is to render content between the tab labels and tab content.
Example:
Usage example:
Contribution
I have an in progress PR that I will link to this issue.