I want to add accessibility features to the Material UI Button.
I expect to use this custom button as follows:
import Button from '#material-ui/core/Button';
function AccessibleButton(props) {
const { accessKey, ariaLabel, isDisabled, label, onClick, tabIndex, variant, size} = props;
return (
<Button
accesskey={accessKey}
aria-label={ariaLabel}
disabled={isDisabled}
className={componentCls}
onClick={onClick}
tabindex={tabIndex}
variant={variant}
size={size}
>
{label}
</Button>
);
};
Aria labels are available for inputs, but don't seem to be for buttons. How do I pass the additional props (accessKey, ariaLabel) into the Material UI Button. How do I do this?
This should work since most of our components forward their excess props. On the corresponding api pages (here https://material-ui.com/api/button/) you will find a table with the apparent props. Below that is a note that tells you what happens with excess props.
It's a bit iffy to navigate (we're working on it) but in the end you'll see that excess props are forwarded to the native element. So <Button aria-label="ariaLabel" /> will render a <button aria-label="ariaLabel" />.
Your code should work.
I have created sandbox where you can inspect the button and see the button will have aria-label and accesskey attribute.
<Button
aria-label="This is aria label"
accessKey="Key"
variant="contained"
color="primary"
>
I'm a button
</Button>
Try inspecting button in below sandbox.
Related
I have the following code to use React To print, a library to print a component:
<ReactToPrint
trigger={() =>
<SqIconButton action={(e)=>e} color={"success"}>
<AiIcons.AiFillPrinter style={{color: 'black',fontSize:'1rem'}}/>
</SqIconButton>
}
content={() => componentRef.current}
/>
And my custom Button SqIconButton reads as follows:
export default function SqIconButton({children,color="primary",fontColor="#000000",action,tip="",disableElevation=false,sxstyle={},classes}){
return(
<Tooltip title={tip}>
<Button
color={color}
variant="contained"
onClick={action}
disableRipple={disableElevation}
className={`TBButton ${classes}`}
sx={sxstyle}
>
{children}
</Button>
</Tooltip>
)
}
In the examples of React To Print code for its trigger nothing is referencing "onclick" property on buttons, examples mostly look like this: <button>print this</button> and if I use this element it actually works. But my custom button does not work as is, so I think I have to pass the onclick event over my action custom property, so I'm trying with action={(e)=>e}, but the button does nothing when I press it.
Documentation says about trigger:
A function that returns a React Component or Element. Note: under the hood, we inject a custom onClick prop into the returned Component/Element. As such, do not provide an onClick prop to the root node returned by trigger, as it will be overwritten
So I don't know if onclick will be overwritten how could I pass this event to a child button component.
Trying to disable a button after the user clicks on it, but from a handler function.
I have referenced these two similar questions:
React Material UI: How to give a button a custom color when disabled?
Change disable attribute in react select with material UI
I thought changing the color would be a good practice step, but that didn't work. When I use color='primary' the button is blue, and that's what I want for the initial state. However, when the page loads, the button is now gray (looks disabled, but the mouse can still click on it).
My original blue button:
<Button id='UploadButton' onClick={uploadButtonClicked}
variant="contained" color="primary">Upload</Button>
My revised button (trying to use state for color):
<Button id='UploadButton' onClick={uploadButtonClicked}
disabled="{uploadButtonDisabled}"
variant="contained"
color="{uploadButtonColor}">Upload</Button>
My state & handler:
const [uploadButtonColor, setUploadButtonColor] =
React.useState('primary');
const [uploadButtonDisabled,
setUploadButtonDisabled] = React.useState('false');
const uploadButtonClicked = () => {
// will post data to a REST API here, then disable the button
setUploadButtonColor('red')
setUploadButtonDisabled('true')
}
Do I need to use color schema to make it look disabled, or can I just add the disabled word, or set disabled to true?
This is how the doc shows a disabled button:
<Button variant="outlined" disabled>
Upload
</Button>
Do not put quotes around the property/substitution values
disabled={isDisabled} not disabled='{isDisabled}' (and same with color).
You can use this :
import Button from "#material-ui/core/Button";
function SampleButtons(props) {
let [isDisabled, setIsDisabled] = React.useState(false)
return (
<React.Fragment>
<Button variant="contained" onClick={() => setIsDisabled(true)} disabled={isDisabled}>Button</Button>
</React.Fragment>
);
}
I've been trying to understand and write code on the Box component in material-UI. (https://material-ui.com/components/box/#box)
I've been trying to override a Button component the two ways it describes in the documentation, but I have no idea how. When I run the code segment using both methods, the button appears but no color change. Then when I try to add an extra Button underneath the clone element code segment I get an error saying 'Cannot read property 'className' of undefined'.
<Box color="primary" clone>
<Button>Click</Button>
<Button>Click</Button>
</Box>
When I add a Button component underneath in the second render props way, the first button just disappears from the DOM completely.
<Box color="secondary">
{props => <Button {...props} > Click </Button>}
<Button color="secondary">Click</Button>
</Box>
Would appreciate an explanation of how overriding underlying DOM elements work.
There are a few issues with the code you've shown in your question.
primary and secondary are not valid colors within the palette. They are valid options for the color prop of Button, but here you are trying to reference colors within the theme's palette object. For this purpose, you need primary.main and secondary.main (which is what Button uses when you specify <Button color="primary">).
Box only supports a single child when using the clone property and it only supports a single child when using the render props approach. In both of your examples you have two children.
Here is the Material-UI source code that deals with the clone option:
if (clone) {
return React.cloneElement(children, {
className: clsx(children.props.className, className),
...spread,
});
}
This is creating a new child element that combines the className generated by Box with any existing class name on the child. It gets at this existing class name via children.props.className, but when there are multiple children then children will be an array of elements and will not have a props property so you get the error:
Cannot read property 'className' of undefined
Here is the Material-UI source code that deals with the render props approach:
if (typeof children === 'function') {
return children({ className, ...spread });
}
When you have more than one child, then typeof children === 'function' will not be true and it won't use the render props approach. In this case, both children just get normal react rendering and trying to render a function doesn't render anything.
Below is a working example that fixes all of these problems by using a single Button child in the clone case and a single function child in the render props case (a function that then renders two Button elements).
import React from "react";
import Button from "#material-ui/core/Button";
import Box from "#material-ui/core/Box";
export default function App() {
return (
<>
<Box color="primary.main" clone>
<Button>Click</Button>
</Box>
<Box color="secondary.main">
{props => (
<>
<Button {...props}> Click </Button>
<Button color="secondary">Click</Button>
</>
)}
</Box>
</>
);
}
I am trying to add a button to the Material UI autocomplete paper by overriding the PaperComponent prop and added a button at the button of the paper, but clicking on the button automatically closes the autocomplete search results
How can i prevent the autocomplete search results Paper from closing on click
Here is a sandbox: https://codesandbox.io/s/material-demo-mxjyi
UPDATE: I didn't notice that the sandbox did not save, now you can see the issue
The problem is the onBlur which occurs before your onClick. Material UI offers to ignore the blur behaviour on debug mode but that happens only if you have a value inside your Autocomplete.
The workaround is to use onMouseDown instead of onClick
Based on your Codesanbox please change the onClick event to onMouseDown event in your <button> component
<button
style={{ margin: "10px", padding: "5px" }}
onMouseDown={() => alert("clicked")}
>
The problem, which is not Material-UI related, was discussed here also
using onMouseDown on the button is not the proper solution here as the user is expecting a different behavior. You can call preventDefault on the paper component to prevent it from closing.
<Autocomplete
//other props...
PaperComponent={(props) => (
<Paper onMouseDown={event => event.preventDefault()}>
<Button>Click</Button>
</Paper>
)}
/>
I am trying to add a FormControl, a Select component and a MenuItem to the action prop of the CardHeader IconButton.
Currently the code looks like this:
Rendering:
<CardHeader
action={
<IconButton
onClick={this.renderFilterRequest()}
>
<Edit />
</IconButton>
}
/>
onClick method:
renderFilterRequest() {
const { selection } = this.state;
return (
<div>
<FormControl>
<Select
value={selection}
onChange={this.handleFilterChange}
>
<MenuItem value='1'>January</MenuItem>
<MenuItem value='2'>February</MenuItem>
</Select>
</FormControl>
</div>
);
}
The error I get is onClick listener to be a function, instead got a value of object type. What is the right way to render the dropdown menu on CardHeader action click?
You are returning some div from from this.renderFilterRequest, And you are also calling the function, so the value of onClick becomes the div. But they were meant to be functions, right?
So it should have been just: onClick={this.renderFilterRequest}.
This function also returned a div but there is no way to attach it to rendering logic in render.
You need to put the MenuItems in your render method and show/hide them depending on the state.
Your onClick listener should be a function that changes the state so that the MenuItems become visible.
Here is a simple demo how this should be done: