microsoft / microsoft-ui-xaml

Windows UI Library: the latest Windows 10 native controls and Fluent styles for your applications
MIT License
6.36k stars 679 forks source link

Proposal: Tabs Control #304

Closed stmoy closed 5 years ago

stmoy commented 5 years ago

The WinUI Team has opened a spec and PR for this feature.

Proposal: Tabs Control

Summary

The Tab control is a way to display a set of tabs and their respective content. Tab controls are useful for displaying several pages (or documents) of content while giving a user the capability to rearrange, open, or close new tabs.

Tabs in Edge

Rationale

As a UI paradigm, Tabs has been around for a long time, and can be found in everything from dialogs to browsers. The focus for this proposal is "document-style" tabs, which enables a user to rearrange, open, and close new tabs.

Tabs in the Edge browser Tabs in Edge

Tabs in Visual Studio Tabs in Visual Studio

Note that "static-style" tabs also exist as a paradigm. "Static-style" tabs are tabs that do not support user interaction beyond switching tabs. UWP already has a solution for static-style tabs in the form of Pivot and NavigationView.

Static-style tabs in WPF Tabs in WPF

A lack of a proper Tab control has been a continual painpoint in UWP, particularly for developers attempting to migrate from WPF.

The XAML platform provides a number of ways to achieve "static-style" tabs in Pivot and top NavigationView. However, these solutions do not well support "document-style" tabs which support user reorder, opening, and closing tabs. The platform does demonstrate how to create "document-style" tabs in the Van Arsdel sample using top NavigationView: Tabs in the Van Arsdel app

Although these workarounds have unblocked apps trying to create "document-style" tabs, they have a number of limitations, including:

Fortunately, the Windows Community Toolkit has created a TabView control that helps address some of the aforementioned pain points.

TabView in WCT

However, the Windows Community Toolkit is a managed/C# project, meaning that customers that don't want to load the CLR or are particularly performance-focused cannot leverage the Windows Community Toolkit implementation.

The goal for this feature proposal is not to "reinvent the wheel" - instead, we hope to take the learnings from the WCT implementation and discussion and build a native control directly into WinUI.

Functional Requirements

# Feature Priority
1. User can switch tabs using common inputs (like ctrl+tab) Must
2. Control has a mode to close tabs Must
3. User can open new tabs Must
4. Control supports tab "tear off" Must
5. Control supports tab "recombination" (both into the same Tab group or between Tab groups) Must
6. Control supports tab reorder Must
7. Control supports data binding to a collection of tabs Must
8. Control supports a custom header/footer Must
9. When not all tabs fit, control provides affordance to access all tabs Must
10. Tab items can have a label and icon Should
11. Tab height, width, and template can be customized Should
12. The app may decide how size the tabs relative to each other (ie. equally sized, sized to content, etc.) Should
13. The control supports Tab Placement with tabs on the Left, Right, or Bottom. Could
14. App can specify specific "unclosable" tabs Could

Important Notes

To replicate the behavior of Microsoft Edge:

<TabControl TabWidthBehavior="Equal"
            CanCloseTabs="True"
            CloseButtonOverlay="OnHover"
            CanDragItems="True"
            CanReorderItems="True"
            TabDraggedOutside="OpenTabInNewWindow">
    <TabControl.TabFooter>
        <Button Content="+" Click="NewTab_Click" />
    </TabControl.TabFooter>
    ...
</TabControl>

The TabControl also supports databinding:

<TabControl ItemsSource="{x:Bind TabItemCollection}" />

TabControl properties and events

Property Type Description
CanCloseTabs bool Default value for the item if it doesn't specify a IsClosable value.
CloseButtonOverlay enum Describes the behavior of the close button. Values are {Auto, OnHover, Persistent}
ItemHeaderTemplate DataTemplate Default template for the item if no template specified.
SelectedTabWidth double The size of the selected tab header.
TabHeader object Content to the left of the tab strip.
TabHeaderTemplate DataTemplate Template for the Header.
TabFooter object Content to the far right of the tab strip.
TabFooterTemplate DataTemplate Template for the Footer.
TabActionContent object Content immediately to the right of the tabs
TabActionContentTemplate DataTemplate Template for the ActionContent.
TabWidthBehavior enum Specifies how the tabs should be sized. Values are {Actual, Equal, Compact}
Event Description
TabClosing Fires when a tab is about to be closed. Can be cancelled to prevent closure.
TabDraggedOutside Fires when a Tab is dragged outside of the Tab bar.

TabItem properties and events

Property Type Description
Content object The main content that appears in the tab.
Header object The content that appears inside the tab itself.
HeaderTemplate DataTemplate Template for the header object.
Icon IconElement Icon for the tab.
IsClosable bool Determines if the tab shows a close button.
Event Description
TabClosing Fires when a tab's close button is clicked.

Parts of a tab item

Position of TabHeader TabFooter and TabActionContent

Open Questions

1. Should Tab Tearoff be something that the control handles or that the app handles? The app will handle it. We will have good samples showing how.

2. Should there be a built-in "Add new tab" button? (I suspect probably not, because the control doesn't own the collection of Tabs.) The app will own the "Add tab" button. In the case of Terminal, for example, they will add a button with a dropdown. Adding an "Add" button doesn't add much value.

3. Should TabItem.Icon be IconElement or IconElementSource? IconElement. IconElementSource is useful when the same icon could appear in multiple places in the tree, which isn't the case here.

  1. How can an app customize that the Selected tab looks like (ie. in Edge)?

  2. The API currently takes a lot of inspiration from the Toolkit. Are there any chances to iterate/improve?

Release Checklists

Prerelease readiness

MikeHillberg commented 5 years ago

Should add a link to the Van Arsdel sample

mdtauk commented 5 years ago

I think the more generic controls from the Toolkit should always find their way ported to C++ and available in the Windows UI Library. Tabs control when it is mature and stable enough should make its way too.

It happened with the Main Menu control :)

michael-hawker commented 5 years ago

Link to Tab Tear-Off sample called out in the proposal as well.

mdtauk commented 5 years ago

Link to Tab Tear-Off sample called out in the proposal as well.

Does tearing off a tab spawn a new AppWindow, new CoreWindow, and how do you handle fallback where the new window APIs are not present?

michael-hawker commented 5 years ago

@mdtauk the sample uses the older multi-windows ApplicationView API currently, the window gets created in a default position instead of where dragged. I've been testing with AppWindow and hope to update the sample for the new SDK.

chigy commented 5 years ago

"Although these workarounds have helped bridge the platform gap from WPF, they have a number of limitations, including:"

You should list keyboarding here as well. This is not just tab key or shortcut keys. Arrowing was something we struggled with when we didn't have tab control and we had to make everyone be consistent in the lack of it.

michael-hawker commented 5 years ago

Comments on open questions from what we've heard in the toolkit:

  1. Should Tab Tearoff be something that the control handles or that the app handles?

I think it's important for the Tab Control to handle the dragging and recombining between TabViews (hosting the same data type) and exposing an drag-out event, with the ability to inspect/intercept.

But I don't know if it's important for the TabView to also directly manage the window lifecycle as that gets more tricky. A developer may also want to customize what happens when dragging a tab out, maybe it just removes it, or creates a special window for just that content vs. a new 'main' window with tabs? Or they may not want to handle having to code for multiple-windows.

It may just be easier to expose the event and have helpers (or leverage existing ones like the ones in Windows Template Studio) to aid in the creation/management of Windows. The trickiest part of this scenario is "data transfer" between threads, which at least the new windowing API should help alleviate.

  1. Should there be a built-in "Add new tab" button? (I suspect probably not, because the control doesn't own the collection of Tabs.)

I think as long as there are adequate header templates and examples, having an implementor add an 'add' button is trivial, so I don't think it needs to be built-in, as then the paradigm would need another event. This is something we had originally thought about too in the toolkit. :)

  1. Should TabItem.Icon be IconElement or IconElementSource?

We used IconElement to mimic the NavigationViewItem's property. Also, IconElementSource is an IconElement so isn't IconElement better as it's broader? It'd be nice if there were an IconElement subclass in WinUI that could just host a straight-up Image though (similar to BitmapIcon but without the forced masking). That way the Icon property could host anything be it a nice Vector Symbol/Font Icon or an ico/png file (think browser type scenario favicon).

  1. How can an app customize that the Selected tab looks like (ie. in Edge)?

Are you talking about exposed style properties which can be modified or like a completely different template for the selected item?

  1. The API currently takes a lot of inspiration from the Toolkit. Are there any chances to iterate/improve?

One feedback item we got was about customizing the space at the end of the tabs. E.g. Should it just be a single template area that can then use left/right horizontal alignment to stick things to the edges vs. two separate areas?

Other questions:

michael-hawker commented 5 years ago

Also forgot to call out for Requirement 9, we had a discussion originally on whether or not to use the Edge model (like the toolkit control currently behaves) or the NavigationView model where it creates a drop-down chevron. We thought maybe in the future we'd support both.

We ended up going with the Edge model as it was simpler to implement, as then we didn't need a SplitObservableCollection type object. I had started working on one as a test, but I wonder if it'd be a useful construct to expose?

michael-hawker commented 5 years ago

@stmoy did you close on the open issues/feedback from above that we had from the toolkit designs?

mdtauk commented 5 years ago

How does the news of Windows Sets abandoning the Edge Tab model, affect how this control may be developed?

With Edge and it's UI pretty much abandoned now in favour of ChromiumEdge (Edgium) do we need/want to rethink the appearance or behaviour of this control to be more suitable to the types of apps that may use it?

Not to mention similar controls like Pivot, and the UWP Ribbon in development. Which is recommended for which use case, and why would someone choose one over the other? Guidance and examples should be clear to answer these questions to avoid confusion or a heavier control being used instead of a performant and lighter one.

First Party controls should use the right control for the right purpose, to try to lead the way in consistent use.

jevansaks commented 5 years ago

On #629 @mdtauk had a feature suggestion:

Maybe an idea for the ToDo list. Tab Placement? Bottom, Left, Right.

michael-hawker commented 5 years ago

Yeah, Tab Placement should be up there in the priority list at some-point to match WPF parity for migration scenarios. It's something we didn't have time to add in the initial Toolkit version either though.

jevansaks commented 5 years ago

When we scoped this feature, it became a non-goal to support the "property sheet tabs" scenario and to focus on the browser-tabs scenario. We do see some overlap with property sheets, but the property sheet metaphor isn't part of fluent design, we have NavigationView (which has Left/Top modes) for that scenario right now.

mdtauk commented 5 years ago

Navigation View is a heavy control, and wants to take up the whole screen. Also Sets is gone from the roadmap, as is the XAML version of Edge.

So there may be scope to re-think the TabView/Control to make it more flexible and useful for the future.

image

image

image

These scenarios could be possible in UWP XAML apps, if the TabView control were to have the ability to hide the add and close buttons.

But there is also Pivot controls, however it only supports pivot headers on top, and Tabs could go on the top, bottom, left or right...

michael-hawker commented 5 years ago

In the toolkit we supported not having the close button, the add button was also something the implementer had to add themselves. This is why we had the TabWidthBehavior property to help setup these different modes between documents and classic tabs. One of the main things we didn't support yet was the tab positioning.

stmoy commented 5 years ago

Thanks for all of the great conversation all! Circling back around...

It's interesting with drag about how to handle dragging into the content area vs. the header as well are both targets? What if the app wants to allow dropping something else in the tab area (like a file from explorer)?

Interesting question. Naively, I'd think that they'd both be the same (large) target as the TabControl hosts both the Tab strip area and the content area. However, this model falls apart when considering apps like Edge (as an example). If Edge was maximized and the user drags a tab out of the tab strip but still over the content because it's max size, the user expects the Tab to create a new window.

Therefore I think we should only have the header area/tab strip be the drag/drop target.

Is "The app may decide how position/size the tabs" talking about the TabStripPlacement property?

This was meant to describe the "TabWidthBehavior" property and enum and not TabStripPlacement. I updated the requirement and added a Tab Placement requirement as well (discussed a bit more below).

Sets is gone from the roadmap, as is the XAML version of Edge.

The primary motivator for this work right now is actually the new Windows Terminal app. We will continue to expand/explore other apps to use the Tab control, but our primary focus is on enabling their scenarios for the moment.

Tab Placement should be up there in the priority list at some-point to match WPF parity for migration scenarios. It's something we didn't have time to add in the initial Toolkit version either though.

Tab Placement is an awesome idea, particularly as it relates to WPF parity. Per the above, however, since we're largely scoping based on what Terminal needs, this ends up being more of a "could" than a "need". That said, I added it to the requirements table above.

These scenarios could be possible in UWP XAML apps, if the TabView control were to have the ability to hide the add and close buttons.

The TabControl supports hiding the close button on the tabs themselves. Additionally, the "Add" button will be provided by the app itself (and not the control), so we expect to be able to make property-style tab scenarios using the control as spec'd above.

mdtauk commented 5 years ago

If the Add tab button is not part of the control, might I suggest a button style and XAML Command be included with the control, to make it easier for people to implement a button consistently wherever the control is used.

michael-hawker commented 5 years ago

@stmoy for the drag scenario, I think there'll be cases where dragging on to the header and the area can be different or the same. It'd be good if a sample could show the dragging for the tear-away, but also for instance dropping a file in the main content area and how to catch that (that may be out of the purview of the control itself, but useful to it's usage).

stmoy commented 5 years ago

button style and XAML Command [for adding a new Tab]

@mdtauk - great idea. I'll add it to the spec.

It'd be good if a sample could show the dragging for the tear-away, but also for instance dropping a file in the main content area and how to catch that

@michael-hawker - Agreed, a sample would be worthwhile. I don't know if it needs to be Tab-specific though, since dragging a file in would be handled by the content area.

stmoy commented 5 years ago

Hi all, just wanted to give you a quick head's up that I'm iterating on the Tabs spec which is currently out for PR. Please add comments to the PR if you have any feedback!

Poopooracoocoo commented 5 years ago

Fingers crossed that they feel more like Chrome's tabs than Edge's.

jevansaks commented 5 years ago

Fingers crossed that they feel more like Chrome's tabs than Edge's.

We want the interaction design to "feel right", so definitely file issues with specific feedback against the preview version so we can get it right before we ship!

mdtauk commented 5 years ago

Not sure if someone like @chigy has already made out a design comp for the TabView Control, but I had a quick go, also demonstrating the Side and Bottom placement options that could come in the future.

Tab Bar

Felix-Dev commented 5 years ago

I don't like that the close-button hover/pressed states change the background of the button and not its foreground. Changing the background adds too much emphasis to the button (and away from the tab title) and the latter would also be much more elegant.

For examples, see the close-button in Edge UWP (foreground changes only) or the tab-audio mute button in Edge (Chromium).

mdtauk commented 5 years ago

I did consider sticking with the foreground change, but felt the background change would be inline with the other controls and titlebar behaviour - but as a default it could just be the foreground.

stmoy commented 5 years ago

@mdtauk - you rock. Thank you for creating these design comps. Although we're not going to do side placement for the first drop of the control, it's great to see what it could look like.

@chigy and I are working together to build out some design comps that line up with the Windows principles (incl. things like rounded corners, standard shadow, etc.) but the design comps you provided will help inspire us.

I don't like that the close-button hover/pressed states change the background of the button and not its foreground. Changing the background adds too much emphasis to the button (and away from the tab title) and the latter would also be much more elegant.

Our current thinking is just to change the foreground color and not the background, as is being suggested here. This has the added benefit of fitting a bit better with the rounded corners that we are considering.

mdtauk commented 5 years ago

The Edge tabs use a background behind the close glyph, but it is smaller than the one I proposed - but the Edgium tabs are not yet supporting any Touch modes.

image

michael-hawker commented 5 years ago

When we were thinking of the side tabs for the design for the toolkit, we were torn between doing them vertically with rotated text as @mdtauk showed or still having them horizontal and taking up a larger margin to the left/right side like OneNote used to before their latest redesign and akin to WPF (which we would thought would be important for compatibility).

So, I'd suggest to keep it as WPF did with the wide-margin and horizontal, but also just make it super simple to support both as shown here, which is another reason to support #546.

mdtauk commented 5 years ago

@michael-hawker I endorse having the vertical list of tabs to the right with the wide margin, and making it easy to rotate them as in Visual Studio.

It will affect the before and after tab spots, but I will look into doing a design mock up when I return home on Monday

mdtauk commented 5 years ago

It will affect the before and after tab spots, but I will look into doing a design mock up when I return home on Monday

I am home, and here is that design: image

mdtauk commented 5 years ago

I have refined a design mockup for the control.

TabControl added Tab Overflow and Tab Sizing

Felix-Dev commented 5 years ago

Like that your tab concept looks much more similar to Edge UWP tabs than Edge Chromium tabs. IMO the look of the tab control should be as close as possible to the tab control in Edge UWP. Acrylic as a tab control background like in Edge UWP also would be quite nice.

I still hope the tab-close button can be made like in Edge UWP, where the button is only displayed for the currently selected tab or on tab mouse hover.

For the WinUI team: @stmoy Apparently the Windows Terminal team can't use acrylic as a background for the tab control (see https://github.com/microsoft/terminal/issues/1375). The terminal team claims that is due to architectural limitations. Is that something the WinUI team could help with? There seem to be quite a few fans of the acrylic background for the tab control as in Edge UWP.

mdtauk commented 5 years ago

@Felix-Dev I know Edgeium is the new design to move towards, but I think the UWP Edge design is a bit nicer - so I wanted to try to bridge that gap

I still hope the tab-close button can be made like in Edge UWP, where the button is only displayed for the currently selected tab or on tab mouse hover.

CloseButtonOverlay Is the property that would do that I think

Felix-Dev commented 5 years ago

@mdtauk To clarify, I'd like to see CloseButtonOverlay = OnHover to become the default of the Tab Control, instead of the close button being constantly shown on all tabs (unnecessarily takes away space from the tab title imo).

mdtauk commented 5 years ago

Always visible is best for touch users, so I think the default should be as inclusive as possible

Felix-Dev commented 5 years ago

Perhaps overlay mode fo the close button could be made dependent on the capabilities of the user's display then?

Not sure if that could somehow be an issue as then there would be a slight visual difference in the Tab Control depending on the display type.

mdtauk commented 5 years ago

Perhaps overlay mode fo the close button could be made dependent on the capabilities of the user's display then?

Not sure if that could somehow be an issue as then there would be a slight visual difference in the Tab Control depending on the display type.

That works for things like flyouts because it can detect the type of input that triggered it, providing larger touch targets if summoned by a touch input.

This doesn't work for controls always visible, as some touch devices will also have a mouse attached.

Developers will be able to change the default option of course, and if an app gets lots of feedback asking for the close button to only show on hover - then they can choose to change it.

mdtauk commented 5 years ago

I have added an idea for Tab overflow image

JustinXinLiu commented 5 years ago

Love this.

Just one small thing. When there’s shadow and rounded corners, we might want a little gap in between the selected tab item and the edge of the background.

mdtauk commented 5 years ago

Love this.

Just one small thing. When there’s shadow and rounded corners, we might want a little gap in between the selected tab item and the edge of the background.

Curious why that would be needed... Doesn't the shadow get cropped by the Window frame? Is it just an aesthetic choice so the shadow is visible above?

mdtauk commented 5 years ago

Tab Sizing image

stmoy commented 5 years ago

@mdtauk : I love seeing these designs! I have a few probing questions:

I'll use these designs to talk with our friends on the Terminal and see what they think. These designs include a few deltas from our current direction, but we will use these to help foster the conversation.


@Felix-Dev : Thank you for the feedback; addressing some of your points below.

Like that your tab concept looks much more similar to Edge UWP tabs than Edge Chromium tabs. IMO the look of the tab control should be as close as possible to the tab control in Edge UWP. Acrylic as a tab control background like in Edge UWP also would be quite nice.

We're actively iterating with various teams (including Terminal and Edge teams) to try to align the Tabs across these app experiences. As we continue to iterate (and implement items like #524), the Tab control design will look more consistent with the updated controls.

I still hope the tab-close button can be made like in Edge UWP, where the button is only displayed for the currently selected tab or on tab mouse hover.

For the short term, we're focusing on implementing the scenarios that Terminal needs and trimming the API surface where appropriate. For v1, we will only support Persistent. That said, I originally spec'd the hover behavior as well because I think it's a great idea. I'm keeping track of these sorts of asks (like x-on-hover, tab placement, etc.) so that we can reassess in the next rev of the control.

For the WinUI team: @stmoy Apparently the Windows Terminal team can't use acrylic as a background for the tab control (see microsoft/terminal#1375). The terminal team claims that is due to architectural limitations. Is that something the WinUI team could help with? There seem to be quite a few fans of the acrylic background for the tab control as in Edge UWP.

We're actively working with the Terminal team. Unfortunately this scenario is a result of a known limitation with Xaml Islands and not with Tabs. We expect that non-Terminal apps should be able to use acrylic background as an "opt-in" feature if the app sets the TabControl.Background to an acrylic brush.

mdtauk commented 5 years ago

Is purple the accent color?

Yes - I didn't want to confuse my design with an official design comp

Is the purpose of the overflow screenshot to show the bumpers? I just want to ensure I'm reading the picture correctly.

Yes, is showing how the left and right buttons would look, and how the tabs would be clipped.

What is the corner radius of the tabs?

4 epx - I know the guidance is 2epx, but the 4epx height of the selected indicator looked better with 4

How tall are the tabs?

40 epx

What font size was used?

14 for the tab title text, 16 for the MDL2 icons

image

mdtauk commented 5 years ago

In Edge Canary there is a flag called New tab-loading animation - edge://flags#new-tab-loading-animation

Part of the spec should include theme and/or implicit animations such as:

Felix-Dev commented 5 years ago

@stmoy

We're actively working with the Terminal team. Unfortunately this scenario is a result of a known limitation with Xaml Islands and not with Tabs.

Is it possible to address this limitation in future versions of Xaml Island? There seems to be a strong desire for background acrylic in the Windows Terminal app, for example. See https://github.com/microsoft/terminal/issues/1375#issuecomment-504625390 and especially the last image in that post (with background acrylic in the titlebar). Also note the many up-votes that post got 😉. Another post with many upvotes here: https://github.com/microsoft/terminal/issues/1375#issuecomment-504644293

Speaking more broadly about the Tabs UI design, also note the supportive reactions to user comments preferring the Edge UWP tabs look over Edge Chromium tab look: https://github.com/microsoft/terminal/issues/1375#issuecomment-504622788 and the post directly below it.

If Edge Chromium tabs are meant to represent the future look of (modern) Windows Tabs those overwhelming user reactions might be a reason to re-think the look of tabs both used in Edge Chromium and in WinUI. (Also adding @chigy here so she can notice those tab UI reactions in the Windows Terminal repo.)

Edit: Also calling the attention of @marb2000 to this topic as it the Windows Terminal team just reaffirmed that they "won't be able to fix" this issue. How is the WinUI team seeing chances for acrylic titlebar (highly requested!) happening for the Windows Terminal? @stmoy

Felix-Dev commented 5 years ago

@marb2000 @stmoy Please comment on the below question:

Also calling the attention of @marb2000 to this topic as the Windows Terminal team just reaffirmed that they "won't be able to fix" this issue [(acrylic titlebar in terminal)]. How is the WinUI team seeing chances for acrylic titlebar (highly requested!) happening for the Windows Terminal?

Felix-Dev commented 5 years ago

@marb2000 @SavoySchuler @jesbis @jevansaks

Pinged everyone one of you guys from the recent community call 😁 About technical acrylic titlebar support in Xaml Islands (Windows Terminal), see my posts above and which were already partly answered by @stmoy

Here are three of the main points taken from my posts and the replies above:

For the WinUI team: Apparently the Windows Terminal team can't use acrylic as a background for the tab control (see microsoft/terminal#1375). The terminal team claims that is due to architectural limitations. Is that something the WinUI team could help with? There seem to be quite a few fans of the acrylic background for the tab control as in Edge UWP.

Reply by @stmoy:

We're actively working with the Terminal team. Unfortunately this scenario is a result of a known limitation with Xaml Islands and not with Tabs. We expect that non-Terminal apps should be able to use acrylic background as an "opt-in" feature if the app sets the TabControl.Background to an acrylic brush.

My question:

Also calling the attention of @marb2000 to this topic as the Windows Terminal team just reaffirmed that they "won't be able to fix" this issue [(acrylic titlebar in terminal)]. How is the WinUI team seeing chances for acrylic titlebar (highly requested!) happening for the Windows Terminal?

Thanks for answering 😁