in packages/react/src/components/Button/BaseButton.tsx [116:263]
public render(): JSX.Element {
const {
ariaDescription,
ariaLabel,
ariaHidden,
className,
disabled,
allowDisabledFocus,
primaryDisabled,
// eslint-disable-next-line deprecation/deprecation
secondaryText = this.props.description,
href,
iconProps,
menuIconProps,
styles,
checked,
variantClassName,
theme,
toggle,
getClassNames,
role,
} = this.props;
const { menuHidden } = this.state;
// Button is disabled if the whole button (in case of splitButton is disabled) or if the primary action is disabled
const isPrimaryButtonDisabled = disabled || primaryDisabled;
this._classNames = getClassNames
? getClassNames(
theme!,
className!,
variantClassName!,
iconProps && iconProps.className,
menuIconProps && menuIconProps.className,
isPrimaryButtonDisabled!,
checked!,
!menuHidden,
!!this.props.menuProps,
this.props.split,
!!allowDisabledFocus,
)
: getBaseButtonClassNames(
theme!,
styles!,
className!,
variantClassName!,
iconProps && iconProps.className,
menuIconProps && menuIconProps.className,
isPrimaryButtonDisabled!,
!!this.props.menuProps,
checked!,
!menuHidden,
this.props.split,
);
const { _ariaDescriptionId, _labelId, _descriptionId } = this;
// Anchor tag cannot be disabled hence in disabled state rendering
// anchor button as normal button
const renderAsAnchor: boolean = !isPrimaryButtonDisabled && !!href;
const tag = renderAsAnchor ? 'a' : 'button';
const nativeProps = getNativeProps(
// eslint-disable-next-line deprecation/deprecation
assign(renderAsAnchor ? {} : { type: 'button' }, this.props.rootProps, this.props),
renderAsAnchor ? anchorProperties : buttonProperties,
[
'disabled', // let disabled buttons be focused and styled as disabled.
],
);
// Check for ariaLabel passed in via Button props, and fall back to aria-label passed in via native props
const resolvedAriaLabel = ariaLabel || (nativeProps as any)['aria-label'];
// Check for ariaDescription, secondaryText or aria-describedby in the native props to determine source of
// aria-describedby. Otherwise default to undefined so property does not appear in output.
let ariaDescribedBy = undefined;
if (ariaDescription) {
ariaDescribedBy = _ariaDescriptionId;
} else if (secondaryText && this.props.onRenderDescription !== nullRender) {
// for buttons like CompoundButton with a valid onRenderDescription, we need to set an ariaDescribedBy
// for buttons that do not render anything (via nullRender), we should not set an ariaDescribedBy
ariaDescribedBy = _descriptionId;
} else if ((nativeProps as any)['aria-describedby']) {
ariaDescribedBy = (nativeProps as any)['aria-describedby'];
}
// If an explicit aria-labelledby is given, use that and we're done.
// If any kind of description is given (which will end up as an aria-describedby attribute)
// and no ariaLabel is specified, set the labelledby element.
// Otherwise, the button is labeled implicitly by the descendent text on the button (if it exists).
let ariaLabelledBy = undefined;
if ((nativeProps as any)['aria-labelledby']) {
ariaLabelledBy = (nativeProps as any)['aria-labelledby'];
} else if (ariaDescribedBy && !resolvedAriaLabel) {
ariaLabelledBy = this._hasText() ? _labelId : undefined;
}
const dataIsFocusable =
(this.props as any)['data-is-focusable'] === false || (disabled && !allowDisabledFocus) || this._isSplitButton
? false
: true;
const isCheckboxTypeRole = role === 'menuitemcheckbox' || role === 'checkbox';
// if isCheckboxTypeRole, always return a checked value.
// Otherwise only return checked value if toggle is set to true.
// This is because role="checkbox" always needs to have an aria-checked value
// but our checked prop only sets aria-pressed if we mark the button as a toggle="true"
const checkedOrPressedValue = isCheckboxTypeRole ? !!checked : toggle === true ? !!checked : undefined;
const buttonProps = assign(nativeProps, {
className: this._classNames.root,
// eslint-disable-next-line deprecation/deprecation
ref: this._mergedRef(this.props.elementRef, this._buttonElement),
disabled: isPrimaryButtonDisabled && !allowDisabledFocus,
onKeyDown: this._onKeyDown,
onKeyPress: this._onKeyPress,
onKeyUp: this._onKeyUp,
onMouseDown: this._onMouseDown,
onMouseUp: this._onMouseUp,
onClick: this._onClick,
'aria-label': resolvedAriaLabel,
'aria-labelledby': ariaLabelledBy,
'aria-describedby': ariaDescribedBy,
'aria-disabled': isPrimaryButtonDisabled,
'data-is-focusable': dataIsFocusable,
// aria-pressed attribute should only be present for toggle buttons
// aria-checked attribute should only be present for toggle buttons with checkbox type role
[isCheckboxTypeRole ? 'aria-checked' : 'aria-pressed']: checkedOrPressedValue,
});
if (ariaHidden) {
buttonProps['aria-hidden'] = true;
}
if (this._isSplitButton) {
return this._onRenderSplitButtonContent(tag, buttonProps);
} else if (this.props.menuProps) {
const { id = `${this._labelId}-menu` } = this.props.menuProps;
assign(buttonProps, {
'aria-expanded': !menuHidden,
'aria-controls': !menuHidden ? id : null,
'aria-haspopup': true,
});
}
return this._onRenderContent(tag, buttonProps);
}