how can I change the layout of this material UI form? - reactjs

I have a checkout form which I made using material UI looking like this:
It seems minor but I'd like to change the layout so that First Name and Last Name etc. are all on the same row, looking more like this (but I'm not sure how to go about it):
Here's the code for my address form component:
return (
<>
<Typography variant="h6" gutterBottom>
Shipping address
</Typography>
<FormProvider {...methods}>
<form
onSubmit={methods.handleSubmit((data) =>
test({
...data,
shippingCountry,
shippingSubdivision,
shippingOption,
})
)}
>
<Grid container spacing={3}>
<FormInput required name="firstName" label="First name" />
<FormInput required name="lastName" label="Last name" />
<FormInput required name="address1" label="Address line 1" />
<FormInput required name="email" label="Email" />
<FormInput required name="city" label="City" />
<FormInput required name="zip" label="Zip / Postal code" />
<Grid item xs={12} sm={6}>
<InputLabel>Shipping Country</InputLabel>
<Select
value={shippingCountry}
fullWidth
onChange={(e) => setShippingCountry(e.target.value)}
>
{Object.entries(shippingCountries)
.map(([code, name]) => ({ id: code, label: name }))
.map((item) => (
<MenuItem key={item.id} value={item.id}>
{item.label}
</MenuItem>
))}
</Select>
</Grid>
<Grid item xs={12} sm={6}>
<InputLabel>Shipping Subdivision</InputLabel>
<Select
value={shippingSubdivision}
fullWidth
onChange={(e) => setShippingSubdivision(e.target.value)}
>
{Object.entries(shippingSubdivisions)
.map(([code, name]) => ({ id: code, label: name }))
.map((item) => (
<MenuItem key={item.id} value={item.id}>
{item.label}
</MenuItem>
))}
</Select>
</Grid>
<Grid item xs={12} sm={6}>
<InputLabel>Shipping Options</InputLabel>
<Select
value={shippingOption}
fullWidth
onChange={(e) => setShippingOption(e.target.value)}
>
{shippingOptions
.map((sO) => ({
id: sO.id,
label: `${sO.description} - (${sO.price.formatted_with_symbol})`,
}))
.map((item) => (
<MenuItem key={item.id} value={item.id}>
{item.label}
</MenuItem>
))}
</Select>
</Grid>
</Grid>
<br />
<div style={{ display: "flex", justifyContent: "space-between" }}>
<Button component={Link} variant="outlined" to="/cart">
Back to Cart
</Button>
<Button type="submit" variant="contained" color="primary">
Next
</Button>
</div>
</form>
</FormProvider>
</>
);
};
And my custom text field component:
import React from "react";
import { TextField, Grid } from "#material-ui/core";
import { useFormContext, Controller } from "react-hook-form";
const FormInput = ({ name, label, required }) => {
const { control } = useFormContext();
const isError = false;
return (
<>
<Controller
control={control}
name={name}
render={({ field }) => <TextField fullWidth label={label} required />}
/>
</>
);
};
export default FormInput;

Looks like you're already using Mui Grid so I think you need to place your <FormInput/> components within a <Grid item/> component. Like this:
<Grid container>
<Grid container direction="row">
<Grid item xs={6} sm={6}>
<FormInput required name="firstName" label="First name" />
</Grid>
<Grid item xs={6} sm={6}>
<FormInput required name="lastName" label="Last name" />
</Grid>
</Grid>
...Another Grid row, and so on...
</Grid>

Related

Getting the same value for dropwown on Oncahange event on react

The below image shows duplicate value getting in two drop down i need to manage the
drop down one by one dynamically on add button click.My requirement is I have need to add multiple experience using the add button.
I have calling a function to createExpDetails() to add the section dynamically when plus button is clicked.The value filled in the drop down is getting from database .The present issue is I am getting the drop downs but when one value in one dropdown is changed it automatically reflects to all the other dropdowns. I need to change the values in dropdown seperately.
const [addfiledexp,setFildExp]=useState('')
const handleChangeexp= (event:SelectChangeEvent,i) =>
{
setFildExp(event.target.value);
}
const createExpDetails=() =>
{
return(addexplist.map((el,i) =>
<div key={i}>
<Box mt={4}>
<Grid container >
<Grid item xs={5} mb={2} mr={8} ml={4}>
<TextField
name='title'
id="title"
variant='outlined'
fullWidth
label="Title"
//value={address}
//onChange={(e: any) => setAddress(e.target.value)}
/>
</Grid>
<Grid item xs={5} mb={2} ml={4}>
<TextField
name='helorganisation'
id="helorganisation"
variant='outlined'
fullWidth
label="Health Care Organization"
// value={address}
//onChange={(e: any) => setAddress(e.target.value)}
/>
</Grid>
<Grid container>
<Grid item xs={5} mb={2} mr={8} ml={4}>
<FormControl fullWidth>
<InputLabel id="demo-simple-select-label">Type</InputLabel>
<Select
labelId="demo-simple-select-label"
id="demo-simple-select"
name='typeselect'
//value= {console.log(addfiledexp)}
value= {addfiledexp}
label="Type"
//onChange={handleChangeexp }
onChange={(e: any) => handleChangeexp(e,i)}
>
{addexptypelist.map((typelist, key) => {
return (<MenuItem value= {typelist.name} ><option key={key} >{typelist.name}</option></MenuItem>);
})}
</Select>
</FormControl>
</Select>
</FormControl>
</Grid>
</Grid>
variant='outlined'
{ addexplist.length >1 && (
<Button className="section-add-button" onClick={()=>handleServiceexpRemove(i)}><CancelIcon className="section-add-icon" /></Button>
)
}
</Box>
</div>
));
}
{createExpDetails()}
<Button className="section-add-button" onClick={() =>addbutton('addexperiance')}><AddCircleIcon className="section-add-icon" /></Button>

How to pass Formik form values via an intermediate function to the handleSubmit event?

Ok, so far I have successfully used the handleSubmit() and could manage to access the updated (user edited) form values but what if you want to have a messagebox prompt user to Save\Discard changes and when user selects the Save button on the messagebox, you want the form's handleSubmit() even gets called and you want to access the form data inside your handleSubmit event? so, for example
const [formValues, setFormValues] = useState({
emailMessageText: emailMessage,
});
const handleSubmit = (initialValues, {e, setSubmitting }) => {
//here in the below messageText I can only access the original value of the
//emailMessageText. i.e. can't get what user had updated post form rendered
let req = {
campusID: campusID,
messageText: initialValues.emailMessageText
};
}
<Formik
enableReinitialize
initialValues={formValues}
onSubmit={handleSubmit}
>
{({
submitForm,
handleBlur,
isSubmitting,
isValid,
touched,
values,
errors,
}) => (
<Form>
<div>
<Grid
container
direction="row"
justify="center"
alignItems="center"
>
<Grid item lg={3} md={5} xs={12}>
<FormControl fullWidth>
<InputLabel htmlFor="primaryCampusID">
Campus
</InputLabel>
<Field
component={Select}
type="text"
name="primaryCampusID"
validate={handleCampusSelection}
inputProps={{
id: "primaryCampusID",
}}
value={campusID}
>
<MenuItem value={0} key={0}>
Select Campus...
</MenuItem>
{campuses.map((option) => (
<MenuItem
value={option.value}
key={option.value}
>
{option.key}
</MenuItem>
))}
</Field>
<FormHelperText error>
<ErrorMessage name="primaryCampusID" />
</FormHelperText>
</FormControl>
</Grid>
<Grid
container
item
lg={12}
md={12}
xs={12}
spacing={5}
justify="space-between"
className={classes.rowSpacing}
>
<Grid item lg={12} md={12} xs={12}>
<FormControl fullWidth>
<Field
component={TextField}
multiline
fullWidth={true}
//label="Email Message"
validate={validateData}
placeholder="Email Message"
name="emailMessageText"
rows="15"
></Field>
<FormHelperText error>
<ErrorMessage name="emailMessageText" />
</FormHelperText>
</FormControl>
</Grid>
<Grid item lg={12} md={12} xs={12}>
<Button
variant="contained"
color="primary"
size="medium"
className={classes.buttonGreen}
startIcon={<EmailIcon />}
disabled={!isFormDataValid}
onClick={() => {
setConfirmOpen(true);
}}
>
Email
</Button>
</Grid>
</Grid>
</Grid>
</div>
</Form>
)}
</Formik>
<ConfirmDialog
title="Send Notification emails?"
open={confirmOpen}
setOpen={setConfirmOpen}
onConfirm={handleSubmit}
>
<Typography style={{ whiteSpace: "pre-line" }}>
{"This job will send notice emails to " +
currentPermitHolders.length +
" members." +
".\n\n" +
" This is a non reversible action. Do you still want to Proceed with the submission?"}
</Typography>
</ConfirmDialog>

Dynamically adding or removing items within a react-hook-forms form and registering the inputs?

I'm trying to implement a rather complicated form that has and date picker and input which the user can add multiple of (or delete). That data then gets added to the overall form on submit. How do I get react-hook-forms to register that little dynamic faux form within the real form?
Here's the faux form inputs:
<AddPackagesStyle>
<Label htmlFor="addedPackages" label="Add Packages" />
<DatePicker
id="dateRange"
selected={startDate}
selectsRange
startDate={startDate}
endDate={endDate}
placeholderText="select dates"
onChange={onDateChange}
/>
<PackageInput
id="PackageSelect"
placeholder="Select Package"
type="text"
value={name}
// #ts-ignore
onChange={(e) =>
// #ts-ignore
setName(e.target.value)
}
/>
<ButtonContainer>
<button type="button" onClick={clearAll}>
Clear
</button>
<button
type="button"
// #ts-ignore
onClick={addPackage}
>
Add
</button>
</ButtonContainer>
</AddPackagesStyle>
These entries get added to an array in a useState hook:
const [addedPackages, setAddedPackages] = useState<any[]>([])
Then this gets rendered in JSX as the add packages:
<ContentSubscriptionWrapper>
{addedPackages.length !== 0 &&
addedPackages.map((addedPackage, idx) => (
// #ts-ignore
<>
<ContentSubscriptionColumn>
{addedPackage.name && addedPackage.name}
</ContentSubscriptionColumn>
<ContentSubscriptionColumn>
{addedPackage.startDate &&
addedPackage.startDate.toString()}
</ContentSubscriptionColumn>
<ContentSubscriptionColumn>
{addedPackage.endDate && addedPackage.endDate.toString()}
</ContentSubscriptionColumn>
<button type="button" onClick={() => removePackage(idx)}>
X
</button>
</>
))}
</ContentSubscriptionWrapper>
So before the form gets submitted, the 'add packages' has to be set. Where do I add the {...register} object to add to the larger form object for submission?
const {
control,
register,
handleSubmit,
formState: { errors },
} = useForm<any>()
const onSubmit = (data: any) => {
console.log(data)
}
I created a CodeSandbox trying to reproduce your use case and used Material UI to get it done quickly, but you should get the idea and can modify it with your own components.
you should let RHF handle all the state of your form
use RHF's useFieldArray for managing (add, remove) your packages/subscriptions - there is no need to use watch here
use a separate useForm for your <AddPackage /> component, this has the benefit that you will have form validation for this sub form (in case it should be a requirement that all fields of <AddPackage /> need to be required) - i added validation in the demo to demonstrate this
AddPackage.tsx
export const AddSubscription: React.FC<AddSubscriptionProps> = ({ onAdd }) => {
const {
control,
reset,
handleSubmit,
formState: { errors }
} = useForm<Subscription>({
defaultValues: { from: null, to: null, package: null }
});
const clear = () => reset();
const add = handleSubmit((subscription: Subscription) => {
onAdd(subscription);
clear();
});
return (
<Card variant="outlined">
<LocalizationProvider dateAdapter={AdapterDateFns}>
<Grid container spacing={1} p={2}>
<Grid item container spacing={1} xs={12}>
<Grid item xs={6}>
<Controller
name="from"
control={control}
rules={{ required: "Required" }}
render={({ field }) => (
<DatePicker
{...field}
label="From"
renderInput={(params) => (
<TextField
{...params}
fullWidth
error={!!errors.from}
helperText={errors.from?.message}
/>
)}
/>
)}
/>
</Grid>
<Grid item xs={6}>
<Controller
name="to"
control={control}
rules={{ required: "Required" }}
render={({ field }) => (
<DatePicker
{...field}
label="To"
renderInput={(params) => (
<TextField
{...params}
fullWidth
error={!!errors.to}
helperText={errors.to?.message}
/>
)}
/>
)}
/>
</Grid>
</Grid>
<Grid item xs={12}>
<Controller
name="package"
control={control}
rules={{ required: "Required" }}
render={({ field: { onChange, ...field } }) => (
<Autocomplete
{...field}
options={packages}
onChange={(e, v) => onChange(v)}
renderInput={(params) => (
<TextField
{...params}
label="Package"
fullWidth
error={!!errors.package}
helperText={errors.package && "Required"}
/>
)}
/>
)}
/>
</Grid>
<Grid item xs={12}>
<Stack spacing={1} direction="row" justifyContent="end">
<Button variant="outlined" onClick={clear}>
Clear
</Button>
<Button variant="contained" onClick={add} type="submit">
Add
</Button>
</Stack>
</Grid>
</Grid>
</LocalizationProvider>
</Card>
);
};
Form.tsx
export default function Form() {
const { control, handleSubmit } = useForm<FormValues>({
defaultValues: {
seats: "",
addOns: false
}
});
const { fields, append, remove } = useFieldArray({
control,
name: "subscriptions"
});
const onSubmit = (data) => console.log("data", data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Grid container spacing={2}>
<Grid item xs={12}>
<Box display="flex" justifyContent="end" gap={1}>
<Button variant="outlined">Cancel</Button>
<Button variant="contained" type="submit">
Save
</Button>
</Box>
</Grid>
<Grid item xs={12}>
<Controller
name="seats"
control={control}
render={({ field }) => (
<TextField {...field} fullWidth label="Seats" />
)}
/>
</Grid>
<Grid item xs={12}>
<AddSubscription onAdd={append} />
</Grid>
<Grid item xs={12}>
<List>
{fields.map((field, index) => (
<ListItem
key={field.id}
secondaryAction={
<IconButton
edge="end"
aria-label="delete"
onClick={() => remove(index)}
>
<DeleteIcon />
</IconButton>
}
>
<ListItemText
primary={field.package.label}
secondary={
<span>
{formatDate(field.from)} - {formatDate(field.to)}
</span>
}
/>
</ListItem>
))}
</List>
</Grid>
<Grid item xs={12}>
<Controller
name="addOns"
control={control}
render={({ field: { value, onChange } }) => (
<FormControlLabel
control={<Checkbox checked={!!value} onChange={onChange} />}
label="Add-ons"
/>
)}
/>
</Grid>
</Grid>
</form>
);
}

React Formik Material UI Autocomplete: How can I populate value inside of autocomplete from localStorage?

So, I'm trying to create form with Formik and Material UI. For all the fields everything is working as it should but the problem is with Autocomplete. I cannot find the way to populate the field from the localStorage. I tried everything, from putting the value props, inputValue, defaultValue, etc but nothing seems to work.
import React from 'react'
import { Grid } from '#material-ui/core'
import { Autocomplete } from '#material-ui/lab'
import { Formik, Form, Field } from 'formik'
import { TextField } from 'formik-material-ui'
import * as yup from 'yup'
import { nationality } from '../../constants/nationality'
import Button from '../Button/Button'
export default function ForeignAddress () {
let localStorageData = localStorage.getItem('foreignAddress'),
retrivedData = JSON.parse(localStorageData)
const handleNextClick = () => {
console.log('clicked next')
}
const handleBackClick = () => {
console.log('clicked back')
}
const validationSchema = yup.object({
streetName: yup.string().required('Street name is required'),
streetNumber: yup.string().required('Street number is required'),
postalCode: yup.string().required('Postal code is required'),
city: yup.string().required('City is required'),
country: yup.string().required('Country is required'),
})
console.log(retrivedData)
return (
<React.Fragment>
<div className="pages-wrapper address">
<Formik
initialValues={retrivedData ? retrivedData : {streetName: '', streetNumber: '', postalCode: '', city: '', coAddress: '', country: ''}}
onSubmit={(data) => {
console.log(data)
localStorage.setItem('foreignAddress', JSON.stringify(data))
handleNextClick()
}}
validationSchema={validationSchema}
>
{({setFieldValue}) => (
<Form>
<Grid container spacing={3}>
<Grid item xs={12} md={8}>
<Field component={TextField} name="streetName" label="Street Name" variant="outlined" fullWidth />
</Grid>
<Grid item xs={12} md={4}>
<Field component={TextField} name="streetNumber" label="Street Number" variant="outlined" fullWidth />
</Grid>
<Grid item xs={12} md={4}>
<Field component={TextField} name="postalCode" label="Postal Code" variant="outlined" fullWidth />
</Grid>
<Grid item xs={12} md={8}>
<Field component={TextField} name="city" label="City" variant="outlined" fullWidth />
</Grid>
<Grid item xs={12} md={6}>
<Field component={TextField} name="coAddress" label="C/O Address" variant="outlined" fullWidth />
</Grid>
<Grid item xs={12} md={6}>
<Autocomplete
id="foreignCountry"
className="country-select"
name="country"
options={nationality}
getOptionLabel={option => option.label}
onChange={(e, value) => {
console.log(value)
setFieldValue("country", value.code)
}}
renderInput={params => (
<Field component={TextField} {...params} name="country" label="Country" variant="outlined" fullWidth/>
)}
/>
</Grid>
</Grid>
<div className="button-wrapper">
<Button label="Back" go="back" handleClick={handleBackClick}/>
<Button label="Next" go="next" type="submit" />
</div>
</Form>
)}
</Formik>
</div>
</React.Fragment>
)
}
EDIT:
Thanks to #Vencovsky i was able to get it done
in case someone in the future needs this here is the working code.
Just change Autocomplete component to
<Autocomplete
id="foreignCountry"
className="country-select"
name="country"
options={nationality}
getOptionLabel={option => option.label}
defaultValue={values.country}
onChange={(e, value) => {
console.log(value)
setFieldValue("country", value)
}}
renderInput={params => (
<Field component={TextField} {...params} name="country" label="Country" variant="outlined" fullWidth/>
)}
/>
and in the Formik props just add values prop
{({setFieldValue, values}) => (
<Form>,...
Edit:
There is a few thing you need to change.
First you can't just store the code to load it later, you need to store everything (the hole value object) from the options.
Change the initial value of country: '' to country: {code: "", label: "", phone: ""} which is all the default value of the options.
Then to load the value correctly you should pass value={values.country} where values comes from formik props.
And on onChange you should save the hole value onChange={(e, value) => {setFieldValue("country", value); }}
But you are also importing and using some wrong things like
<Field
component={TextField}
{...params}
name="country"
label="Country"
variant="outlined"
fullWidth
/>
Where Field is form formik and TextField from formik material ui.
Not sure why you use it like that, but I have changed it.
Here is a working example

Using Ref inside stateless functional component is not working in React JS

I am developing a React JS Web Application. I am new to react js. Now, I am trying to use Ref inside the stateless functional component to retrieve the input value. I followed some of the solutions I found online.
This is my component
const Login = (props) => {
const {
classes,
width
} = props;
// Flip container to column on mobile screens.
const panelDirection = width === 'xs' ? 'column' : 'row';
let emailInput = null;
let passwordInput = null;
return (
<Grid
container
direction="row"
spacing={0}
justify="center"
alignItems="center"
className={classes.background}
>
<Grid item sm={10} xs={12} className={scss.panel}>
<form className="full-height" action="post">
<Grid direction={panelDirection} container spacing={0}>
<Grid
item
sm={6}
xs={12}
>
<Card className={classNames(scss.card, classes['primary-card'])}>
<CardContent className={scss['signup-content']}>
<img src={logoImage} className={scss['signup-logo']} alt="logo" />
<Typography variant="headline" component="h2" gutterBottom>
Web Portal
</Typography>
</CardContent>
<CardActions>
<Button fullWidth href="/register" color="secondary" variant="raised">Create an account</Button>
</CardActions>
</Card>
</Grid>
<Grid
item
sm={6}
xs={12}
>
<Card className={scss.card}>
<CardContent>
<TextField
ref={(input) => { emailInput = input }}
label="Email Address"
fullWidth
/>
<TextField
ref={(input) => { passwordInput = input }}
label="Password"
fullWidth
margin="normal"
type="password"
/>
</CardContent>
<CardActions className={scss['login-actions']}>
<Button href="/login" color="primary" variant="raised">Login</Button>
<Button href="/forgot-password">Forgot Password</Button>
</CardActions>
</Card>
</Grid>
</Grid>
</form>
</Grid>
</Grid>
);
};
As you can see, I am using ref to retrieve the values of email and password input fields. But, when I run, it is still giving me this error.
Warning: Stateless function components cannot be given refs. Attempts to access this ref will fail.
So, how can I fix my code? How can I use Ref correctly in the stateless function component?
Obviously, I followed this, How can I attach to a stateless component's ref in React?
I tried using the class as well. It is giving me the same error. This is the class version of my component.
class Login extends React.Component {
submitForm = e => {
e.preventDefault();
}
constructor(props)
{
super(props);
this.emailInput = React.createRef();
this.passwordInput = React.createRef();
}
render () {
const { classes, width } = this.props;
// Flip container to column on mobile screens.
const panelDirection = width === 'xs' ? 'column' : 'row';
return (
<Grid
container
direction="row"
spacing={0}
justify="center"
alignItems="center"
className={classes.background}
>
<Grid item sm={10} xs={12} className={scss.panel}>
<form className="full-height" action="post" onSubmit={this.submitForm}>
<Grid direction={panelDirection} container spacing={0}>
<Grid
item
sm={6}
xs={12}
>
<Card className={classNames(scss.card, classes['primary-card'])}>
<CardContent className={scss['signup-content']}>
<img src={logoImage} className={scss['signup-logo']} alt="logo" />
<Typography variant="headline" component="h2" gutterBottom>
Web Portal
</Typography>
</CardContent>
<CardActions>
<Button fullWidth href="/register" color="secondary" variant="raised">Create an account</Button>
</CardActions>
</Card>
</Grid>
<Grid
item
sm={6}
xs={12}
>
<Card className={scss.card}>
<CardContent>
<TextField
ref={this.emailInput}
label="Email Address"
fullWidth
/>
<TextField
ref={this.passwordInput}
label="Password"
fullWidth
margin="normal"
type="password"
/>
</CardContent>
<CardActions className={scss['login-actions']}>
<Button type="submit" color="primary" variant="raised">Login</Button>
<Button href="/forgot-password">Forgot Password</Button>
</CardActions>
</Card>
</Grid>
</Grid>
</form>
</Grid>
</Grid>
)
}
}
Login.propTypes = {
classes: PropTypes.shape({}).isRequired,
width: PropTypes.string.isRequired
};
export default compose(withWidth(), withStyles(themeStyles, { withTheme: true }))(Login);
If you insist in using stateless component (which to me they are great) you should use a callback to retrieve the value of your input:
// Login.js
const Login = (props) => {
const {
classes,
width,
onChange, // <- get the callback here
} = props;
...
return (
...
<TextField
name="email"
onChange={onChange}
label="Email Address"
fullWidth
/>
<TextField
name="password"
onChange={onChange}
label="Password"
fullWidth
margin="normal"
type="password"
/>
...
);
// Somewhere to include Login
class LoginPage extends Component {
...
handleInputChange({ target }) {
...
console.log(target.name, target.value);
}
render (
<Login onChange={this.handleInputChange} ... />
)
}
// Or connect it to Redux
const mapDispatchToProps = dispatch => {
const updateLoginInputValues = ({ target }) => dispatch(updateLoginInputValues(target.name, target.value)));
return {
onChange: updateLoginInputValues,
}
};
const connectedLogin = connect(null, mapDispatchToProps)(Login
The only part that you can improve is basically either handling the values by a state management or directly with React. Other than this you need to address the state at some point and you can't keep all of you components stateless.
State less component means it does not contains state, component only updates through props. So you can use class container for that. here is the solution...
import React, { Component } from "react";
class Login extends Component {
constructor(props) {
super(props);
this.emailInput = React.createRef();
this.passwordInput = React.createRef();
}
render() {
const { classes, width } = this.props;
// Flip container to column on mobile screens.
const panelDirection = width === "xs" ? "column" : "row";
return (
<Grid container direction="row" spacing={0} justify="center" alignItems="center" className={classes.background}>
<Grid item sm={10} xs={12} className={scss.panel}>
<form className="full-height" action="post">
<Grid direction={panelDirection} container spacing={0}>
<Grid item sm={6} xs={12}>
<Card className={classNames(scss.card, classes["primary-card"])}>
<CardContent className={scss["signup-content"]}>
<img src={logoImage} className={scss["signup-logo"]} alt="logo" />
<Typography variant="headline" component="h2" gutterBottom>
Web Portal
</Typography>
</CardContent>
<CardActions>
<Button fullWidth href="/register" color="secondary" variant="raised">
Create an account
</Button>
</CardActions>
</Card>
</Grid>
<Grid item sm={6} xs={12}>
<Card className={scss.card}>
<CardContent>
<TextField ref={this.emailInput} label="Email Address" fullWidth />
<TextField ref={this.passwordInput} label="Password" fullWidth margin="normal" type="password" />
</CardContent>
<CardActions className={scss["login-actions"]}>
<Button href="/login" color="primary" variant="raised">
Login
</Button>
<Button href="/forgot-password">Forgot Password</Button>
</CardActions>
</Card>
</Grid>
</Grid>
</form>
</Grid>
</Grid>
)
}
}
export default Login;
Now you can get value of the textfields like this
this.emailInput.current.value and this.passwordInput.current.value

Resources