Skip to content

Commit

Permalink
[@mantine/core] Input: Fix incorrect Input.Error role, connect Input.…
Browse files Browse the repository at this point in the history
…Description and Input.Error to the input element with aria-describedby (#3146)
  • Loading branch information
rtivital committed Dec 12, 2022
1 parent 366b17e commit feeea02
Show file tree
Hide file tree
Showing 5 changed files with 25 additions and 6 deletions.
3 changes: 2 additions & 1 deletion src/mantine-core/src/Input/Input.tsx
Expand Up @@ -98,7 +98,7 @@ export const _Input = forwardRef<HTMLInputElement, InputProps>((props, ref) => {
pointer,
...others
} = useComponentDefaultProps('Input', defaultProps, props);
const { offsetBottom, offsetTop } = useInputWrapperContext();
const { offsetBottom, offsetTop, describedBy } = useInputWrapperContext();

const { classes, cx } = useStyles(
{
Expand Down Expand Up @@ -135,6 +135,7 @@ export const _Input = forwardRef<HTMLInputElement, InputProps>((props, ref) => {
ref={ref}
required={required}
aria-invalid={invalid}
aria-describedby={describedBy}
disabled={disabled}
className={cx(classes[`${variant}Variant`], classes.input, {
[classes.withIcon]: icon,
Expand Down
2 changes: 1 addition & 1 deletion src/mantine-core/src/Input/InputError/InputError.tsx
Expand Up @@ -31,7 +31,7 @@ export const InputError = forwardRef<HTMLDivElement, InputErrorProps>((props, re
);

return (
<Text className={cx(classes.error, className)} ref={ref} role="alert" {...others}>
<Text className={cx(classes.error, className)} ref={ref} {...others}>
{children}
</Text>
);
Expand Down
2 changes: 2 additions & 0 deletions src/mantine-core/src/Input/InputWrapper.context.ts
Expand Up @@ -3,11 +3,13 @@ import { createContext, useContext } from 'react';
interface InputWrapperContextValue {
offsetTop: boolean;
offsetBottom: boolean;
describedBy: string;
}

const InputWrapperContext = createContext<InputWrapperContextValue>({
offsetBottom: false,
offsetTop: false,
describedBy: undefined,
});

export const InputWrapperProvider = InputWrapperContext.Provider;
Expand Down
6 changes: 6 additions & 0 deletions src/mantine-core/src/Input/InputWrapper/InputWrapper.test.tsx
Expand Up @@ -78,4 +78,10 @@ describe('@mantine/core/InputWrapper', () => {
expect(queries.getLabel(label)).toHaveAttribute('for', 'test-id');
expect(queries.getLabel(div)).not.toHaveAttribute('for');
});

it('generates correct ids for description and error', () => {
const { container } = render(<InputWrapper {...defaultProps} id="test45" />);
expect(queries.getDescription(container)).toHaveAttribute('id', 'test45-description');
expect(queries.getError(container)).toHaveAttribute('id', 'test45-error');
});
});
18 changes: 14 additions & 4 deletions src/mantine-core/src/Input/InputWrapper/InputWrapper.tsx
Expand Up @@ -116,6 +116,11 @@ export const InputWrapper = forwardRef<HTMLDivElement, InputWrapperProps>((props
};

const isRequired = typeof withAsterisk === 'boolean' ? withAsterisk : required;
const errorId = id ? `${id}-error` : errorProps?.id;
const descriptionId = id ? `${id}-description` : descriptionProps?.id;
const hasError = !!error && typeof error !== 'boolean';
const _describedBy = `${hasError ? errorId : ''} ${description ? descriptionId : ''}`;
const describedBy = _describedBy.trim().length > 0 ? _describedBy.trim() : undefined;

const _label = label && (
<InputLabel
Expand All @@ -137,6 +142,7 @@ export const InputWrapper = forwardRef<HTMLDivElement, InputWrapperProps>((props
{...descriptionProps}
{...sharedProps}
size={descriptionProps?.size || sharedProps.size}
id={descriptionProps?.id || descriptionId}
>
{description}
</InputDescription>
Expand All @@ -150,6 +156,7 @@ export const InputWrapper = forwardRef<HTMLDivElement, InputWrapperProps>((props
{...sharedProps}
size={errorProps?.size || sharedProps.size}
key="error"
id={errorProps?.id || errorId}
>
{error}
</InputError>
Expand All @@ -172,10 +179,13 @@ export const InputWrapper = forwardRef<HTMLDivElement, InputWrapperProps>((props

return (
<InputWrapperProvider
value={getInputOffsets(inputWrapperOrder, {
hasDescription: !!_description,
hasError: !!_error,
})}
value={{
describedBy,
...getInputOffsets(inputWrapperOrder, {
hasDescription: !!_description,
hasError: !!_error,
}),
}}
>
<Box className={cx(classes.root, className)} ref={ref} {...others}>
{content}
Expand Down

0 comments on commit feeea02

Please sign in to comment.