I'm trying to make a form using Material UI and React. This is what I have so far:
import React from 'react'
import {Button, TextField} from '#material-ui/core'
import AddIcon from '#material-ui/icons/Add'
import PropTypes from 'prop-types'
class AddItem extends React.Component {
state = {
text: ''
}
handleChange = e => {
this.setState({text: e.target.value})
}
render() {
return (
<form onSubmit={this.props.onSubmit(this.state.text)}>
<TextField id="task" label="Task" placeholder="e.g. Feed the fish" value={this.state.text}
onChange={this.handleChange} color="secondary" variant="outlined" size="small"/>
<Button color="secondary" variant="outlined" endIcon={<AddIcon/>} size="large">
Add
</Button>
</form>
)
}
}
AddItem.propTypes = {
onSubmit: PropTypes.func.isRequired
}
export default AddItem
The result is the following screenshot:
But wait! Can you see that? The Button height and the TextField height are just so slightly misaligned! (By 2.5px I think). Is there any way to fix this?
This is better than earlier, where the TextField was a lot bigger than the Button (my fix was size="small" on the TextField).
How can I make sure that the TextField and the Button are the same height?
I know that in Bulma there's something like a level component that helps out with that, so is there any similar solution in Material UI?
You can make your custom <Button> styled as you want.
Lets create <StyledButton> by overwriting style (padding) of outlined and large variant of button.
import { withStyles } from "#material-ui/core/styles";
const styles = {
outlinedSizeLarge: {
padding: "6px 21px" // default is "7px 21px" https://github.com/mui-org/material-ui/blob/master/packages/material-ui/src/Button/Button.js#L202
}
};
const StyledButton = withStyles(styles)(Button);
Then you can use it in your component:
<form onSubmit={this.props.onSubmit(this.state.text)}>
<TextField id="task" label="Task" placeholder="e.g. Feed the fish" value={this.state.text} onChange={this.handleChange} color="secondary" variant="outlined" size="small"/>
<StyledButton color="secondary" variant="outlined" endIcon={<AddIcon/>} size="large">Add</StyledButton>
</form>
Result:
Live demo
Did you try to use variant attribute with value outlined?
<Button variant='outlined' size='small'>Add</Button>
Related
I have a JS file (react) that looks like this:
import { Grid, TextField, makeStyles } from '#material-ui/core'
import React from 'react'
import {useState} from 'react'
//remove this function and refresh. see magic.
const useStyle = makeStyles(theme => ({
root:{
'& .MuiFormControl-root':{
width : '80%',
margin : theme.spacing(.75)
}
}
}))
const initialFormValues = {
id:0,
name:'',
username:'',
email:''
}
export default function EntryForm() {
const [values, setvalues] = useState(initialFormValues)
return (
<form className={useStyle().root}>
<Grid container>
<Grid item>
<TextField
size='small'
variant='outlined'
label='name'
value={values.name} />
<TextField
size='small'
variant='outlined'
label='username'
value={values.username} />
<TextField
size='small'
variant='outlined'
label='email'
value={values.email} />
</Grid>
<Grid item>
</Grid>
</Grid>
</form>
)
}
This works fine, and invoked, the fields get rendered along with it's parent components.
However, changing first line to:
import { Grid, TextField, makeStyles } from '#mui/material'
and refreshing the browser makes the whole page empty. Apparently, this happens specifically with makeStyles from '#mui/material' usage. Using Grid and Textfield from '#mui/material' only doesn't cause that.
What is happening here?
As per docs you should import makeStyles from #mui/styles.
Please try updating the import statement as:
import { makeStyles } from "#mui/styles";
I'm building a website that uses "RTL (Right To Left) language", so I implemented react-hook-form, but react hook form uses only "LTR" forms like so...
In here I'm using the HTML attribute (dir="RTL") in my page, so all the text is "RTL" except the react hook form how can I fix this?.
import { TextField, Grid } from "#material-ui/core";
import { useFormContext, Controller } from "react-hook-form";
const FormInput = ({ name, label }) => {
const { control } = useFormContext();
return (
<Grid item xs={12} sm={6}>
<Controller
as={TextField} control={control} fullWidth name={name} label={label} required defaultValue=""/>
</Grid>
)
}
export default FormInput;
this is my FormInput component, I export this component to my address form component
import { useForm, FormProvider } from "react-hook-form";
<FormProvider>
<form>
<FormInput name="firstName" label="الإسم الأول (first name)" />
<FormInput name="lastName" label="اسم العائلة (last name)" />
</form>
</FormProvider>
this is my address form component.
I'm trying to apply styles to my React form. I'm using withStytles from Material UI.
The styles however are not taking into affect. I tried testing the code in my first <DialogContentText> in the code below, but it's not working.
EDIT: edited my code to reflect David's answer.
import React, { Component, Fragment } from 'react';
import { withStyles } from '#material-ui/core/styles';
import Button from '#material-ui/core/Button';
import Dialog from '#material-ui/core/Dialog';
import DialogActions from '#material-ui/core/DialogActions';
import DialogContent from '#material-ui/core/DialogContent';
import DialogContentText from '#material-ui/core/DialogContentText';
import DialogTitle from '#material-ui/core/DialogTitle';
import IconButton from '#material-ui/core/IconButton';
import AddCircleIcon from '#material-ui/icons/AddCircle';
import TextField from '#material-ui/core/TextField';
import FormHelperText from '#material-ui/core/FormHelperText';
import Select from '#material-ui/core/Select';
import MenuItem from '#material-ui/core/MenuItem';
import InputLabel from '#material-ui/core/InputLabel';
import FormControl from '#material-ui/core/FormControl';
const styles = theme => ({
formControl: {
width: 500
},
selectEmpty: {
marginTop: theme.spacing(2),
},});
export default class extends Component {
state = {
open: false,
bucket: {
name:'',
category: '',
about: '',
}
}
handleToggle = () => {
this.setState({
open: !this.state.open
})
}
handleChange = name => ({ target: { value } }) => {
this.setState({
bucket:{
...this.state.bucket,
[name]: value,
}
})
}
render() {
const { open, bucket: { name, category, about } } = this.state;
const { classes } = this.props;
return <Fragment>
<IconButton color="primary" size="large" onClick={this.handleToggle}>
<AddCircleIcon/>
</IconButton>
<Dialog open={open} onClose={this.handleToggle} aria-labelledby="form-dialog-title">
<DialogTitle id="form-dialog-title">Create your Bucket</DialogTitle>
<DialogContent>
<DialogContentText>
Get started! Make your bucket by telling us a little bit more.
</DialogContentText>
<form>
<TextField
id="filled-password-input"
label="Bucket Title"
value={name}
variant="filled"
onChange={this.handleChange('name')}
margin="normal"
required = "true"
className = {classes.formControl}
/>
<br/>
<br/>
<FormControl>
<InputLabel htmlFor="category"> What type of Bucket </InputLabel>
<Select
labelId="demo-simple-select-helper-label"
id="demo-simple-select-helper"
value={category}
onChange={this.handleChange('category')}
required = "true"
>
<MenuItem value={'personal'}> Personal </MenuItem>
<MenuItem value={'social'}> Social </MenuItem>
</Select>
</FormControl>
<FormHelperText>Is this your personal or social Bucket?</FormHelperText>
<TextField
id="filled-password-input"
label="About"
multiline
rows="5"
value={about}
variant="filled"
onChange={this.handleChange('about')}
margin="normal"
/>
<FormHelperText>Will this be your tech stock watchlist?</FormHelperText>
<br/>
<br/>
</form>
</DialogContent>
<DialogActions>
<Button
color="primary"
variant="raised"
onClick={this.handleSubmit}
>
Create Bucket
</Button>
</DialogActions>
</Dialog>
</Fragment>
}
}
export withStyles(styles)(YourComponent);
How would I be able to apply these styles to my code below? Thank you for assistance.
TL;DR: You are trying to use a React Hook const classes = useStyles; within a class component. Also, useStyles is a function, not an object.
NL;PR: Hooks only work on functional components (useStyles() hooks are obtained via makeStyles() instead of withStyles()). You apply HOC withStyles(YourComponent) to your class component not your styles, so you can access const {classes, ...rest} = this.props; in the render() method.
It should look like this:
const styles = theme => ({
formControl: {
width: 500
},
selectEmpty: {
marginTop: theme.spacing(2),
},});
class YourComponent extends PureComponent {
//...
render(){
const {classes, ...rest} = this.props;
// now your can access classes.formControl ...
}
}
export withStyles(styles)(YourComponent);
I'm trying to use my custom TextField in my RegisterForm with Yup but he's dosnt work.
All time I have a message "⚠ Champ obligatoire." after click on Submit I don't understand why but is good with a simple input.
RegisterPage.js
import React, { useRef } from "react";
import { useForm } from "react-hook-form";
import Button from "../../lib/Button";
import TextField from "../../lib/TextField";
import * as yup from "yup";
const SignupSchema = yup.object().shape({
firstName: yup.string().required("⚠ Champ obligatoire."),
});
export default function Home() {
const { register, handleSubmit, errors, watch } = useForm({
validationSchema: SignupSchema,
});
const onSubmit = (data) => console.log(data);
console.log(errors);
return (
<div style={styles.inputForm}>
<p>Inscription</p>
<form style={{ marginTop: "40%" }} onSubmit={handleSubmit(onSubmit)}>
<label style={styles.label} htmlFor="firstName">
Prénom
</label>
<TextField
style={styles.input}
name="firstName"
placeholder="Toto"
type="text"
ref={register}
/>
<br />
{errors.firstName && (
<p style={styles.error}>{errors.firstName.message}</p>
)}
<br />
<Button
style={{ marginTop: 10 }}
type="submit"
onClick={handleSubmit(onSubmit)}>
Termine ton incription
</Button>
</form>
</div>
);
}
My CustomTextField
CustomTextfield.js
import React from "react";
import PropTypes from "prop-types";
import TextField from "#material-ui/core/TextField";
function CustomField({ InputLabelProps = {}, ...props }) {
return (
<TextField
InputLabelProps={{ shrink: true, ...InputLabelProps }}
{...props}
/>
);
}
CustomField.propTypes = {
classes: PropTypes.object.isRequired,
};
export default CustomField;
Thanks in advance!
You need to use inputRef instead of ref on TextField. ref will be applied to the outermost element which will be the div rendered by FormControl; and this won't be any help with the yup integration. inputRef will forward the ref to the input element.
<TextField
style={styles.input}
name="firstName"
placeholder="Toto"
type="text"
inputRef={register}
/>
Related documentation: https://material-ui.com/api/text-field/#props
I have created a form with material ui, and I would like to clear it. I have searched for answers/solutions across Stackoverflow but all of them are not working for me.
I have tried by using setstate but it not result to clear the form.
I want to know how to do this using onclick event of the button.
import React, { Component } from "react";
import {
Grid,
TextField,
AppBar,
Typography,
Toolbar,
Button
} from "#material-ui/core";
export class MyInput extends Component {
constructor(props) {
super(props);
this.state = {
first_name: "",
last_name: ""
};
}
handle_input = (name, value) => {
let cur_state = this.state;
cur_state[name] = value;
this.setState(cur_state);
};
render() {
return (
<Grid container justify="center">
<Grid item md={4}>
<TextField
defaultValue={this.state.first_name}
variant="outlined"
label="First Name"
onKeyUp={(e) => {
this.handle_input("first_name", e.target.value);
}}
/>
</Grid>
<Grid item md={4}>
<TextField
defaultValue={this.state.last_name}
variant="outlined"
label="Last Name"
onKeyUp={(e) => {
this.handle_input("last_name", e
.target.value);
}}
/>
</Grid>
<Grid item md={4}>
<div
style={{
width: "100%",
padding: "10px",
display: "flex",
justifyContent: "space-between"
}}
>
<Button color="primary" variant="contained">
save
</Button>
<Button
color="secondary"
variant="contained"
onClick={() => {
this.setState({
first_name: "",
last_name: ""
});
}}
>
cancel
</Button>
</div>
</Grid>
</Grid>
);
}
}
export default MyInput;
Inside the TextField set a value,
<TextField
value={this.state.first_name}
defaultValue={this.state.first_name}
variant="outlined"
label="First Name"
onKeyUp={(e) => {
this.handle_input("first_name", e.target.value);
}}
/>
Then when you want to clear it, just use setState
this.setState({ first_name: '' })
Edit:
In fact, you can delete defaultValue as the default is an empty string anyways, which is what you're using.
<TextField
value={this.state.first_name}
variant="outlined"
label="First Name"
onKeyUp={(e) => {
this.handle_input("first_name", e.target.value);
}}
/>
It may be worth reading the react docs, basically you're wanting to override the form's internal state, which you do by using the value prop
I dont know if this will help as I am pretty new to react myself but you could try making a functional component instead of a class to help reduce the amount of code you need, i would do something like this
import React, {useState} from "react";
export default function MyInput(props) {
const [myState, setMyState] = useState(props);
function clearState() {
setMyState.first_name("")
setMyState.last_name("")
}
return (
//Your grid code here
)
//set your button on click to this
onClick = {() => {clearState()}}
Look into writing components like this its quite nice. Again this will need tweaking but may be a point in the right direction.