Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{

@github-actions github-actions Bot May 29, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🕵🏾‍♀️ visual changes to review in the Visual Change Report

vr-tests-react-components/Menu Converged - submenuIndicator slotted content 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Menu Converged - submenuIndicator slotted content.default.submenus open.chromium.png 413 Changed
vr-tests-react-components/Positioning 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Positioning.Positioning end.updated 2 times.chromium.png 124 Changed
vr-tests-react-components/ProgressBar converged 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/ProgressBar converged.Indeterminate + thickness.default.chromium.png 40 Changed
vr-tests-react-components/TagPicker 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/TagPicker.disabled - Dark Mode.disabled input hover.chromium.png 658 Changed

There were 1 duplicate changes discarded. Check the build logs for more information.

"type": "minor",
"comment": "feat: add optional `icon` slot to Label, rendered before the label content",
"packageName": "@fluentui/react-label",
"email": "egianoglio@microsoft.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ The v9 API does not support many of the features offered in v0. Some could poten
| | `design` | |
| `disabled` | | `disabled` |
| | `fluid` | |
| | `icon` | |
| | `icon` | `icon` |
| | `iconPosition` | |
| | `image` | |
| | `imagePosition` | |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,14 @@ The Label component should be simple as shown below. It will just need the text
<Label required="**">
Label
</Label>

<Label icon={<InfoRegular />}>Label</Label>
```

## Variants

- A Label can be rendered with an asterisk or custom text when is set as `required`.
- A Label can render an optional `icon` slot before its content.

## API

Expand All @@ -83,13 +86,16 @@ See API at [Label.types.ts](./src/components/Label/Label.types.ts).
### Public

```tsx
<Label required>I'm a Label</Label>
<Label required icon={<InfoRegular />}>
I'm a Label
</Label>
```

### DOM

```tsx
<label {/*Label*/} class="...">
<span {/*icon*/} class="..."><svg>...</svg></span>
I'm a Label
<span {/*required*/} class="...">*</span>
</label>
Expand All @@ -99,6 +105,7 @@ See API at [Label.types.ts](./src/components/Label/Label.types.ts).

```tsx
<slots.root {...slotProps.root}>
{state.icon && <slots.icon {...slotProps.icon} />}
{state.children}
<slots.required {...slotProps.required} />
</slots.root>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export type LabelProps = Omit<ComponentProps<LabelSlots>, 'required'> & {
export type LabelSlots = {
root: Slot<'label'>;
required?: Slot<'span'>;
icon?: Slot<'span'>;
};

// @public
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ describe('Label', () => {
testOptions: {
'has-static-classnames': [
{
props: { required: 'Required Test' },
props: { required: 'Required Test', icon: 'Icon Test' },
},
],
Comment on lines 12 to 16
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ export type LabelProps = Omit<ComponentProps<LabelSlots>, 'required'> & {
export type LabelSlots = {
root: Slot<'label'>;
required?: Slot<'span'>;

/**
* Optional icon rendered alongside the label text, before the label content.
*/
icon?: Slot<'span'>;
};

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const renderLabel_unstable = (state: LabelBaseState): JSXElement => {

return (
<state.root>
{state.icon && <state.icon />}
{state.root.children}
{state.required && <state.required />}
</state.root>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,15 @@ export const useLabel_unstable = (props: LabelProps, ref: React.Ref<HTMLElement>
* @param ref - reference to root HTMLElement of Label
*/
export const useLabelBase_unstable = (props: LabelBaseProps, ref: React.Ref<HTMLLabelElement>): LabelBaseState => {
const { disabled = false, required = false, ...rest } = props;
const { disabled = false, required = false, icon, ...rest } = props;
return {
disabled,
required: slot.optional(required === true ? '*' : required || undefined, {
defaultProps: { 'aria-hidden': 'true' },
elementType: 'span',
}),
components: { root: 'label', required: 'span' },
icon: slot.optional(icon, { elementType: 'span' }),
components: { root: 'label', required: 'span', icon: 'span' },
root: slot.always(
getIntrinsicElementProps('label', {
ref: ref as React.Ref<HTMLLabelElement>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type { SlotClassNames } from '@fluentui/react-utilities';
export const labelClassNames: SlotClassNames<LabelSlots> = {
root: 'fui-Label',
required: 'fui-Label__required',
icon: 'fui-Label__icon',
};

/**
Expand All @@ -31,6 +32,11 @@ const useStyles = makeStyles({
paddingLeft: tokens.spacingHorizontalXS,
},

withIcon: {
display: 'inline-flex',
alignItems: 'center',
},

small: {
fontSize: tokens.fontSizeBase200,
lineHeight: tokens.lineHeightBase200,
Expand All @@ -52,18 +58,60 @@ const useStyles = makeStyles({
},
});

/**
* Styles for the icon slot
*/
const useIconStyles = makeStyles({
base: {
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
borderRadius: tokens.borderRadiusMedium,
backgroundColor: tokens.colorNeutralBackground3,
color: tokens.colorNeutralForeground3,
marginRight: tokens.spacingHorizontalXS,
},

small: {
fontSize: tokens.fontSizeBase200,
height: tokens.fontSizeBase500,
width: tokens.fontSizeBase500,
},

smallSemibold: {
height: tokens.fontSizeBase400,
width: tokens.fontSizeBase400,
},

medium: {
fontSize: tokens.fontSizeBase400,
height: tokens.fontSizeBase500,
width: tokens.fontSizeBase500,
},

large: {
fontSize: tokens.fontSizeBase500,
height: tokens.fontSizeBase600,
width: tokens.fontSizeBase600,
borderRadius: tokens.borderRadiusLarge,
marginRight: tokens.spacingHorizontalSNudge,
},
});

/**
* Apply styling to the Label slots based on the state
*/
export const useLabelStyles_unstable = (state: LabelState): LabelState => {
const styles = useStyles();
const iconStyles = useIconStyles();
// eslint-disable-next-line react-hooks/immutability
state.root.className = mergeClasses(
labelClassNames.root,
styles.root,
state.disabled && styles.disabled,
styles[state.size],
state.weight === 'semibold' && styles.semibold,
state.icon && styles.withIcon,
state.root.className,
);

Expand All @@ -77,5 +125,16 @@ export const useLabelStyles_unstable = (state: LabelState): LabelState => {
);
}

if (state.icon) {
// eslint-disable-next-line react-hooks/immutability
state.icon.className = mergeClasses(
labelClassNames.icon,
iconStyles.base,
iconStyles[state.size],
state.size === 'small' && state.weight === 'semibold' && iconStyles.smallSemibold,
state.icon.className,
);
}

return state;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import * as React from 'react';
import type { JSXElement } from '@fluentui/react-components';
import { Label } from '@fluentui/react-components';
import { InfoRegular } from '@fluentui/react-icons';

export const Icon = (): JSXElement => {
return (
<Label icon={<InfoRegular />} required>
Label with icon
</Label>
);
};

Icon.parameters = {
docs: {
description: {
story: 'A Label can render an optional `icon` slot before its content.',
},
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export { Size } from './LabelSize.stories';
export { Weight } from './LabelWeight.stories';
export { Disabled } from './LabelDisabled.stories';
export { Required } from './LabelRequired.stories';
export { Icon } from './LabelIcon.stories';

const meta = {
title: 'Components/Label',
Expand Down
Loading