microsoft / microsoft-ui-xaml

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

Proposal: Badge Control for enabling badging in NavigationView #2963

Closed anawishnoff closed 3 years ago

anawishnoff commented 4 years ago

Proposal: Create Badge control

Summary

This proposal is based off of #2140. Thanks to @joshkoon for starting this discussion.

Badging is the least intrusive and most intuitive way to display notifications or bring focus to something within an app. A Badge control should be a small piece of UI that can be added into an app and customized to display a number, symbol, or a simple dot. This control would be its own entity, but could be easily integrated into a number of controls and control items, providing a wide variety of use cases.

Rationale

Scope

Capability Priority
Easily integrate into the UI without being intrusive. Must
Have the ability and flexibility to be used in or attached to any control Must
Provide a consistent badging experience and interface across all WinUI apps Must
Display one of the following: a dot, number, or one of the approved glyphs. Should
Change based on user activity - badges should not be static, and should only be used if they change with user interaction (i.e. must disappear if items have been seen) Should
This badge control won't take over the current app-level badging/notification system. Won't

Important Notes

Design Considerations

The Badge control should be a simple enough design that it can be integrated into various controls and templates. The design has to be able to scale and support different use cases including but not limited to: general notifications, new content indication, update available, and error/issue/warning. It also has to be flexible enough so that it's visually appealing for items/controls with and without icons.

Below are very rough outlines of what a Badge control might look like. This design will clearly need to be revised and iterated upon, but the design below represents a scalable Badge that's integrated into different scenarios.

Thanks to @mdtauk who provided the original mockups for a Badge control in #2140.

In this example, badges are integrated into NavigationView items.

badge-ex-1

For TabView, the Badge can be integrated in multiple places within a tab. This will be up to the developer’s discretion as they include a Badge in their ItemTemplate.

image

The below examples shows a MenuBar where a nested item has a warning Badge.

badging-ex-3

The below example shows a command bar where the Badge could represent new sharing options available.

badging-ex-4

This example shows a TreeView with a Badge on a certain document. The Badge could indicate that there's been activity or changes on the document.

badging-ex-5

Flexibility and guidance

The Badge control has three different options for what to display, as mentioned above: dot, numeric, and glyph. These three types allow for flexibility while still keeping the Badge visuals highly consistent across WinUI apps. With consistency as a core priority, the team would provide specific guidance on how and when to use a Badge. Some guidance topics would include:

Example Markup

Badge control should have Type and Value properties. Type would be one of three values: Dot, Numerical, or Glyph. Value would be a number for numerical badges or the corresponding name of the symbol to be used in a glyph badge.

A Badge can be created with the following markup:

<Badge Type="Numeric" Value="{x:Bind numUnread}"/>

Implementation notes

There are a few methods with which we could implement a Badge control:

  1. Adorners This is an API that was available in WPF. This will require adding new APIs to WinUI to allow for the use of adorners.

Adorners will allow for the Badge to be added ("adorned") onto another control without otherwise interfering with the control, and the Badge will render separately in a different layer. Using adorners will also make it easier for a developer to add a Badge control wherever they want, rather than editing a control template each time they want to add a Badge. Badge would be a built-in Adorner.

Here's a basic example of how a Badge would be added to a "File" MenuBarItem via adorners:

var adorner = AdornerLayer.GetAdornerLayer(MenuFileBtn);
adorner.Add(new Badge(MenuFileBtn));
  1. Decorators A common example of a decorator class in UWP is Border. In your markup, you wrap it around the element you'd like it to interact with. This wouldn't require adding new APIs to WinUI as Adorners would, but it might be more tedious to use in the long run as the developer would have to drill down into the item that they'd like to put a Badge on and find the exact element on which the Badge should overlay.

Here's a basic example of how a Badge would be added to the icon of a NavigationViewItem if it was a decorator class:


<NavigationView>
    <NavigationView.MenuItems>
        <NavigationViewItem Content="Home" Icon="Home"/>

        <NavigationViewItem Content="Inbox">
            <Badge Type="Numeric" Value="{x:Bind numUnread}">
                <NavigationViewItem.Icon>
                    <SymbolIcon Symbol="Mail"/>
                 </NavigationViewItem.Icon>
           </Badge>
       </NavigationViewItem>

    </NavigationView.MenuItems>
</NavigationView>

Use cases, control integration, and prioritization

There are lots of situations and controls in which a Badge control could be useful. To support these scenarios, it's important that the Badge control remains a standalone entity that's flexible enough to fit into lots of different templates.

Example Badge scenarios:

Integrating Badge directly into NavigationView

Since NavigationView will likely be the most popular scenario in which a Badge will be used, I'm proposing that the Badge control be integrated into the control template of NavigationViewItem when the control is shipped. This will allow developers to get familiar with the control through NavigationView and continue to use it in other controls as they wish. If future feature requests come in for direct Badge integration into other controls, that can happen as well. Otherwise, the process of manually adding a Badge to an ItemTemplate or control template should be designed to be relatively pain-free.

The Badge control would be built into NavigationViewItem's control template as an overlay on the item's Icon. NavigationViewItem would have a Badge property that would take in a Badge with Type and Value properties. These Type and Value properties would be bound to the Badge in the control template.

From the developer's side, they'd just have to set NavigationViewItem.Badge to a Badge object with the correct properties:

<NavigationView x:Name="NavView">
        <NavigationView.MenuItems>

            <!-- ... -->

            <NavigationViewItem Tag="inbox" Content="Inbox">
                <NavigationViewItem.Icon>
                    <FontIcon FontFamily="Segoe MDL2 Assets" Glyph="&#xE715;"/>
                </NavigationViewItem.Icon>
                <NavigationViewItem.Badge>
                    <Badge Type="Numerical" Value="{x:Bind numUnread}"/>
                </NavigationViewItem.Badge>
            </NavigationViewItem>

            <!-- ... -->

        </NavigationView.MenuItems>
</NavigationView>

More details on how Badges would change states, increment, etc. will be covered in a spec. The implementation details for integrating a Badge into other controls will also be covered in a spec.

Questions and Answers

If we didn't have this, how hard is it to do this yourself? Would be good to see how much simpler/easier/better we're making it?

While it's possible to manually add a badge into a NavigationView or other control, it's not necessarily trivial. It'll likely consist of re-templating the item so that the content presenter includes a Badge provided by a style resource. And that's the bare minimum for the "dot" badge - for numerical or symbolic badges, there would be more binding involved and the process would get trickier.

Having a built-in Badge control simplifies this process, and also provides an important consistency across all WinUI apps. If every app that needs badging implements it manually, the badging look and experience will differ greatly across apps and interfere with the streamlined consistency provided by WinUI controls.

What would the type of the NavigationViewItem.Badge property be?

The current design is to have the Badge property be of type Badge rather than type Object. This allows the platform to offer the three approved kinds of badges - dot, symbol, or numeric. The three options give flexibility while also ensuring consistency across WinUI apps.

Open questions

mdtauk commented 3 years ago

Is there any merit in adding something you mentioned in the previous issue, about having a BadgedIcon where you place an Icon, and it includes provision for a badge in it?

Also should this continue to use the MDL2 icons initially, or move on to using Fluent UI System Icons? MDL2 icons include smaller badge sized icons, but the Fluent ones support 12px scaled icons more widely?

Adorners and Decorators sound like a very powerful concept, which could be useful way beyond simple badging scenarios. They could be useful for floating attached UI in Hololens situations for instance. Badging should be a non-interactive element, so no hit testing.

Should there be a mode with the badge to display it as simply text? Like for numeric values without having the container shape around it?

How would/should accessibility tools announce the badge status or numeric value?

michael-hawker commented 3 years ago

@anawishnoff is this the corresponding spec? https://github.com/microsoft/microsoft-ui-xaml/blob/48758d2022ccb3cd1f26d7df43b20d75342019bf/specs/InfoBadge/InfoBadge-spec.md

I was curious why it's IsOpen vs. using Visibility? Also, is there a numeric spill-over capability like showing 9+ even if the number is 11?

It seems like originally there was overlays of the badge on top of the icon as well. Is that an exercise left to developers to figure out or will there also be an IconSource type compatible interop component which can be used to display both an Icon and a Badge (which may also have it's own Icon...).

Thanks!

anawishnoff commented 3 years ago

@michael-hawker Yup, that's the spec that should be associated with this proposal. Not sure if there's a way to link them...

I believe IsOpen was chosen over Visibility because that follows the precedent of other pop-up like controls such as TeachingTip. Also, the IsOpen property will not be hiding the InfoBadge by setting the Visibility on it, it will do so by changing the opacity.

The InfoBadge won't have that numeric spill-over feature built-in. The reasoning for this was that it was hard to determine the exact number where we should set the cut off, taking into account that different locales may have different sized characters and different developers may want to set different cut-offs. Currently, there's no max value for the numeric InfoBadge.

In the spec you can see mockups where in a Left-Compact or icon only NavigationView, the InfoBadge will appear overlayed on the icon. That layout is built in when you use the NavigationViewItem.InfoBadge property. If you're using InfoBadge outside of NavigationView or in a different control, you'll be in charge of positioning it where you'd like it. At this time there aren't plans to add any functionality to IconSource, but that does sound like an interesting idea.

michael-hawker commented 3 years ago

@anawishnoff you can use the Linked Pull Requests on the right panel of the issue here to connect them. 🙂 Seems like I don't have permissions with my Triage roll to do it...

anawishnoff commented 3 years ago

@michael-hawker Well that was easy enough! Thanks!

xperiandri commented 3 years ago

I think that IsOpen is not relevant to this type of control. Changing visibility will be enough.

And there should be a property like MaxDigits to display 9+, 99+ or 999+ whatever a developer considers as relevant.

mdtauk commented 3 years ago

I think that IsOpen is not relevant to this type of control. Changing visibility will be enough.

And there should be a property like MaxDigits to display 9+, 99+ or 999+ whatever a developer considers as relevant.

I wonder if the Trimming property could be used somehow?

gabbybilka commented 3 years ago

As an FYI this is now in a 2.7 pre-release with NavView integration and preset styles 🎨

If you'd like to check out the control let us know how the integration went and any additional feedback you have for the control. If you find a bug, please feel free to open a new issue to track 🐞

gabbybilka commented 3 years ago

Control added in WinUI 2.7

opcodewriter commented 2 years ago

Sorry to revamp this, but I'm confused. What about WinUI 3? There's no NavigationViewItem.InfoBadge in WinUI3. Thanks!

gabbybilka commented 2 years ago

The WinUI 3 team wasn't able to port over the changes from WinUI 2.7 before shipping Windows App SDK 1.0. We are prioritizing adding missing functionality from WinUI 2.x like InfoBadge and Mica to WASDK 1.1.