New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.
Already on GitHub? Sign in to your account
[docs] Final polish on Base docs - formatting and style consistency #33156
Changes from all commits
b25aac5
60c7b09
f78c1f7
faa5479
f0e814e
8907b17
3bfbee7
1cf8a39
1a37b54
92ab404
0a43be4
e3e73f5
b33f538
33a8f84
0962d4b
b972bfa
3306811
e9f972a
4f65b04
2d9af7b
d69cf1b
9b749ed
36b20c6
99ab8dd
6c157fe
ee9f893
baeb70d
694fabb
dc0aa94
e08fe8e
8434af2
3e59932
0ff49f1
d946d65
ea9be13
ab316e4
fbbe9fe
77cb8de
270264d
b08d157
076ab43
504d75c
103e518
d201ba3
02f961a
5b637a5
a062cb6
58effd5
03bf91f
7bbaf7e
387e9e6
bdd7cf7
2cd1227
0a71943
c519089
0d4b0d1
38cfeea
8f485ec
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -1,43 +1,149 @@ | ||||||
--- | ||||||
product: base | ||||||
title: Unstyled React Badge component | ||||||
title: Unstyled React Badge component and hook | ||||||
components: BadgeUnstyled | ||||||
githubLabel: 'component: badge' | ||||||
packageName: '@mui/base' | ||||||
--- | ||||||
|
||||||
# Unstyled badge | ||||||
|
||||||
<p class="description">The `BadgeUnstyled` component generates a small label that is attached to its children elements.</p> | ||||||
<p class="description">The BadgeUnstyled component generates a small label that is attached to its child element.</p> | ||||||
|
||||||
```js | ||||||
## Introduction | ||||||
|
||||||
A badge is a small descriptor for UI elements. | ||||||
It typically sits on or near an element and indicates the status of that element by displaying a number, icon, or other short set of characters. | ||||||
|
||||||
The `BadgeUnstyled` component creates a badge that is applied to its child element. | ||||||
|
||||||
{{"component": "modules/components/ComponentLinkHeader.js", "design": false}} | ||||||
|
||||||
## Component | ||||||
|
||||||
### Usage | ||||||
|
||||||
After [installation](/base/getting-started/installation/), you can start building with this component using the following basic elements: | ||||||
|
||||||
```jsx | ||||||
import BadgeUnstyled from '@mui/base/BadgeUnstyled'; | ||||||
|
||||||
export default function MyApp() { | ||||||
return ( | ||||||
<BadgeUnstyled>{/* the element that the badge is attached to */}</BadgeUnstyled> | ||||||
); | ||||||
} | ||||||
``` | ||||||
|
||||||
{{"component": "modules/components/ComponentLinkHeader.js", "design": false}} | ||||||
### Basics | ||||||
|
||||||
`BadgeUnstyled` wraps around the UI element that it's attached to. | ||||||
For instance, if the badge indicates the number of emails in an inbox, then the component will be structured like this: | ||||||
|
||||||
```jsx | ||||||
<BadgeUnstyled> | ||||||
<MailIcon /> | ||||||
</BadgeUnstyled> | ||||||
``` | ||||||
|
||||||
### Anatomy | ||||||
|
||||||
The `BadgeUnstyled` component is composed of a root `<span>` that houses the element that the badge is attached to, followed by a `<span>` slot to represent the badge itself: | ||||||
|
||||||
```html | ||||||
<span class="BaseBadge-root"> | ||||||
<!-- the element the badge is attached to is nested here --> | ||||||
<span class="BaseBadge-badge">badge content</span> | ||||||
</span> | ||||||
``` | ||||||
|
||||||
### Slot props | ||||||
|
||||||
:::info | ||||||
The following props are available on all non-utility Base components. | ||||||
See [Usage](/base/getting-started/usage/) for full details. | ||||||
::: | ||||||
|
||||||
Use the `component` prop to override the root slot with a custom element: | ||||||
|
||||||
```jsx | ||||||
<BadgeUnstyled component="div" /> | ||||||
``` | ||||||
|
||||||
Use the `components` prop to override any interior slots in addition to the root: | ||||||
|
||||||
```jsx | ||||||
<BadgeUnstyled components={{ Root: 'div', Badge: 'div' }} /> | ||||||
``` | ||||||
|
||||||
:::warning | ||||||
If the root element is customized with both the `component` and `components` props, then `component` will take precedence. | ||||||
::: | ||||||
|
||||||
Use the `componentsProps` prop to pass custom props to internal slots. | ||||||
The following code snippet applies a CSS class called `my-badge` to the badge slot: | ||||||
|
||||||
```jsx | ||||||
<BadgeUnstyled componentsProps={{ badge: { className: 'my-badge' } }} /> | ||||||
``` | ||||||
|
||||||
:::warning | ||||||
Note that `componentsProps` slot names are written in lowercase (`root`) while `components` slot names are capitalized (`Root`). | ||||||
::: | ||||||
|
||||||
## Hook | ||||||
|
||||||
```jsx | ||||||
import { useBadge } from '@mui/base/BadgeUnstyled'; | ||||||
``` | ||||||
|
||||||
The `useBadge` hook lets you apply the functionality of `BadgeUnstyled` to a fully custom component. | ||||||
It returns props to be placed on the custom component, along with fields representing the component's internal state. | ||||||
|
||||||
Hooks _do not_ support [slot props](#slot-props), but they do support [customization props](#customization). | ||||||
|
||||||
:::info | ||||||
Hooks give you the most room for customization, but require more work to implement. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I recently realized another use case for hooks - if you're building a component library that can be customized further by developers (e.g. using the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you think this is worth mentioning on all pages? Or maybe it would be better suited for the Usage page? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suppose having it just on the Usage page should be enough. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sounds good. I'll add it to #33272 |
||||||
With hooks, you can take full control over how your component is rendered, and define all the custom props and CSS classes you need. | ||||||
|
||||||
You may not need to use hooks unless you find that you're limited by the customization options of their component counterparts鈥攆or instance, if your component requires significantly different [structure](#component-slots). | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would this be better?
Suggested change
|
||||||
::: | ||||||
|
||||||
## Customization | ||||||
|
||||||
:::info | ||||||
The following features can be used with both components and hooks. | ||||||
For the sake of simplicity, demos and code snippets primarily feature components. | ||||||
::: | ||||||
|
||||||
### Badge content | ||||||
|
||||||
The `badgeContent` prop defines the content that's displayed inside the badge. | ||||||
When this content is a number, there are additional props you can use for further customization鈥攕ee the [Numerical badges section](#numerical-badges) below. | ||||||
|
||||||
## Basic usage | ||||||
The following demo shows how to create and style a typical numerical badge that's attached to a generic box element: | ||||||
|
||||||
{{"demo": "UnstyledBadge.js", "defaultCodeOpen": false}} | ||||||
|
||||||
## Badge visibility | ||||||
### Badge visibility | ||||||
|
||||||
You can control the visibility of a `BadgeUnstyled` by using the `invisible` prop. | ||||||
Setting a badge to `invisible` does not actually hide it鈥攊nstead, this prop adds the `MuiBadge-invisible` class to the badge, which you can target with styles to hide however you prefer: | ||||||
You can control the visibility of a badge by using the `invisible` prop. | ||||||
Setting a badge to `invisible` does not actually hide it鈥攊nstead, this prop adds the `BaseBadge-invisible` class to the badge, which you can target with styles to hide however you prefer: | ||||||
|
||||||
{{"demo": "BadgeVisibility.js"}} | ||||||
|
||||||
## Numerical badges | ||||||
### Numerical badges | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not have it as a h2? As far as I understand, this section makes sense regardless of the component or hook API chosen.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, that does present a unique challenge for organizing the pages that cover components + hooks. We might have to rethink how those pages are structured. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, agree, it's not an obvious decision. I provided a bit more context for this feedback in #33156 (review). |
||||||
|
||||||
The following props are useful when `badgeContent` is a number. | ||||||
|
||||||
### The showZero prop | ||||||
#### The showZero prop | ||||||
|
||||||
By default, badges automatically hide when `badgeContent={0}`. You can override this behavior with the `showZero` prop: | ||||||
By default, badges automatically hide when `badgeContent={0}`. | ||||||
You can override this behavior with the `showZero` prop: | ||||||
|
||||||
{{"demo": "ShowZeroBadge.js"}} | ||||||
|
||||||
### The max prop | ||||||
#### The max prop | ||||||
|
||||||
You can use the `max` prop to set a maximum value for `badgeContent`. | ||||||
The default is 99. | ||||||
|
@@ -47,6 +153,6 @@ The default is 99. | |||||
## Accessibility | ||||||
|
||||||
Screen readers may not provide users with enough information about a badge's contents. | ||||||
To make your `BadgeUnstyled` accessible, you must provide a full description with `aria-label`: | ||||||
To make your badge accessible, you must provide a full description with `aria-label`, as shown in the demo below: | ||||||
|
||||||
{{"demo": "AccessibleBadges.js", "defaultCodeOpen": false}} | ||||||
{{"demo": "AccessibleBadges.js"}} | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that we could keep the preview disabled. It doesn't explain how the feature works, so I feel noise for developers
Suggested change
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,37 +8,131 @@ waiAria: https://www.w3.org/WAI/ARIA/apg/patterns/button/ | |
|
||
# Unstyled button | ||
|
||
<p class="description">Buttons allow users to take actions and make choices with a single tap.</p> | ||
<p class="description">Buttons let users take actions and make choices with a single tap.</p> | ||
|
||
## Basic button | ||
## Introduction | ||
|
||
```js | ||
`ButtonUnstyled` replaces the native HTML `<button>` element. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It could be interesting to explain why (The value proposition for a developer to replace a native button) Or maybe it's better to say "extends" it. |
||
|
||
{{"component": "modules/components/ComponentLinkHeader.js", "design": false}} | ||
|
||
## Component | ||
|
||
### Usage | ||
|
||
After [installation](/base/getting-started/installation/), you can start building with this component using the following basic elements: | ||
|
||
```jsx | ||
import ButtonUnstyled from '@mui/base/ButtonUnstyled'; | ||
|
||
<ButtonUnstyled>Button</ButtonUnstyled>; | ||
export default function MyApp() { | ||
return <ButtonUnstyled>{/* button text */}</ButtonUnstyled>; | ||
} | ||
``` | ||
|
||
### Basics | ||
|
||
`ButtonUnstyled` behaves similarly to the native HTML `<button>`, so it wraps around the text that will be displayed on its surface. | ||
|
||
The following demo shows how to create and style two basic buttons. | ||
Notice that the second button cannot be clicked due to the `disabled` prop: | ||
|
||
{{"demo": "UnstyledButtonsSimple.js", "defaultCodeOpen": true}} | ||
|
||
## Customizing the root element | ||
### Anatomy | ||
|
||
The `ButtonUnstyled` component is composed of a root `<button>` slot with no interior slots: | ||
|
||
```html | ||
<button class="BaseButton-root"> | ||
<!-- button text goes here --> | ||
</button> | ||
``` | ||
|
||
By default, the `ButtonUnstyled` component renders a native `button` HTML element. | ||
You can override this by setting the `component` or `components.Root` prop. | ||
### Slot props | ||
|
||
:::info | ||
The following props are available on all non-utility Base components. | ||
See [Usage](/base/getting-started/usage/) for full details. | ||
::: | ||
|
||
Use the `component` prop to override the root slot with a custom element: | ||
|
||
```jsx | ||
<ButtonUnstyled component="div" /> | ||
``` | ||
|
||
If you provide a non-interactive element such as a `<span>`, the `ButtonUnstyled` component will automatically add the necessary accessibility attributes. | ||
|
||
Use the `components` prop to override any interior slots in addition to the root: | ||
|
||
```jsx | ||
<ButtonUnstyled components={{ Root: 'div' }} /> | ||
``` | ||
|
||
:::warning | ||
If the root element is customized with both the `component` and `components` props, then `component` will take precedence. | ||
::: | ||
|
||
Use the `componentsProps` prop to pass custom props to internal slots. | ||
The following code snippet applies a CSS class called `my-button` to the root slot: | ||
|
||
```jsx | ||
<ButtonUnstyled componentsProps={{ root: { className: 'my-button' } }} /> | ||
``` | ||
|
||
:::warning | ||
Note that `componentsProps` slot names are written in lowercase (`root`) while `components` slot names are capitalized (`Root`). | ||
::: | ||
|
||
Compare the attributes on the `<span>` in this demo with the `ButtonUnstyled` from the previous demo: | ||
|
||
{{"demo": "UnstyledButtonsSpan.js"}} | ||
|
||
### Complex customization | ||
:::warning | ||
If a `ButtonUnstyled` is customized with a non-button element (i.e. `<ButtonUnstyled component="span" />`), it will not submit the form it's in when clicked. | ||
Similarly, `<ButtonUnstyled component="span" type="reset">` will not reset its parent form. | ||
::: | ||
|
||
## Hook | ||
|
||
```js | ||
import { useButton } from '@mui/base/ButtonUnstyled'; | ||
``` | ||
|
||
The `useButton` hook lets you apply the functionality of `ButtonUnstyled` to a fully custom component. | ||
It returns props to be placed on the custom component, along with fields representing the component's internal state. | ||
|
||
Hooks _do not_ support [slot props](#slot-props), but they do support [customization props](#customization). | ||
|
||
:::info | ||
Hooks give you the most room for customization, but require more work to implement. | ||
With hooks, you can take full control over how your component is rendered, and define all the custom props and CSS classes you need. | ||
|
||
You may not need to use hooks unless you find that you're limited by the customization options of their component counterparts鈥攆or instance, if your component requires significantly different [structure](#component-slots). | ||
::: | ||
|
||
The `useButton` hook requires the `ref` of the element it's used on. | ||
|
||
The following demo shows how to build the same buttons as those found in the [Basic usage section](#basic-usage), but with the `useButton` hook: | ||
|
||
{{"demo": "UseButton.js", "defaultCodeOpen": true}} | ||
|
||
## Customization | ||
|
||
:::info | ||
The following features can be used with both components and hooks. | ||
For the sake of simplicity, demos and code snippets primarily feature components. | ||
::: | ||
|
||
### Custom elements | ||
|
||
`ButtonUnstyled` accepts a wide range of custom elements beyond HTML elements. | ||
You can even use SVGs, as the following demo illustrates: | ||
|
||
{{"demo": "UnstyledButtonCustom.js", "defaultCodeOpen": false}} | ||
|
||
## Focus on disabled buttons | ||
### Focus on disabled buttons | ||
|
||
Similarly to the native HTML `<button>` element, the `ButtonUnstyled` component can't receive focus when it's disabled. | ||
This may reduce its accessibility, as screen readers won't be able to announce the existence and state of the button. | ||
|
@@ -51,28 +145,11 @@ This should be used whenever the disabled button needs to be read by screen read | |
|
||
MUI Base uses this prop internally in [menu items](/base/react-menu/), making it possible to use the keyboard to navigate to disabled items (in compliance with [ARIA guidelines](https://www.w3.org/WAI/ARIA/apg/practices/keyboard-interface/#x6-7-focusability-of-disabled-controls)). | ||
|
||
The following demo shows how the `focusableWhenDisabled` prop works鈥攗se the <kbd class="key">Tab</kbd> key to navigate within this document to see that only the second button accepts the focus: | ||
|
||
{{"demo": "UnstyledButtonsDisabledFocus.js"}} | ||
|
||
The `focusWhenDisabled` prop works the same when the root slot is customized, except that the `aria-disabled` attribute is used no regardless of the prop's state. | ||
The `focusableWhenDisabled` prop works the same when the root slot is customized, except that the `aria-disabled` attribute is used no regardless of the prop's state. | ||
The ability to receive focus is controlled internally by the `tabindex` attribute. | ||
|
||
{{"demo": "UnstyledButtonsDisabledFocusCustom.js"}} | ||
|
||
## The useButton hook | ||
|
||
```js | ||
import { useButton } from '@mui/base/ButtonUnstyled'; | ||
``` | ||
|
||
The `useButton` hook lets you use the functionality of `ButtonUnstyled` in other components. | ||
It returns props to be placed on a custom button element, along with fields representing the internal state of the button. | ||
|
||
The `useButton` hook requires the `ref` of the element it's used on. | ||
Additionally, you need to provide the `component` prop (unless you intend to use the native HTML `<button>`). | ||
|
||
{{"demo": "UseButton.js", "defaultCodeOpen": true}} | ||
|
||
## Limitations | ||
|
||
If a `ButtonUnstyled` is customized with a non-button element (i.e. `<ButtonUnstyled component="span" />`), it will not submit the form it's in when clicked. | ||
Similarly, `<ButtonUnstyled component="span" type="reset">` will not reset its parent form. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When landing on https://deploy-preview-33156--material-ui.netlify.app/base/react-badge you need to scroll a lot before you can find an actual demo of the component or one that you can copy and paste into your project. It contrasts with what we had before https://mui.com/base/react-badge/ or https://www.radix-ui.com/docs/primitives/components/tooltip. So I conclude that we miss an introduction demo, maybe under
### Basics
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is reinforced by this feedback https://mui-org.slack.com/archives/C0170JAM7ML/p1659457895980239?thread_ts=1658732401.469249&cid=C0170JAM7ML
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is a good point. We could definitely use a basic intro demo here, and probably for some other Base components as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will raise this discussion at the next team meeting, seeing
it feels nice to see a full demo first before everything else. It can even then turn into an SEO hack https://www.notion.so/mui-org/Page-image-generator-75bc177fefe64c0b899a42a6f919a907.