All I want to achieve is a page that has a header that reads: "Survey Start" and then a user select interface under that. I am envisioning a very simple component:
export class Survey extends Component {
state = {
}
render() {
return (
<React.Fragment>
<h2>Survey Start</h2>
<Survey sorcery here>
</React.Fragment>
)
}
Then my App.js runs this.
I aim to replace "survey sorcery" with the "some important helper text" version of MaterialUI's user select. I directly copied from the javascript source that was provided. Seen here:
https://material-ui.com/components/selects/
I thought it would be as simple as copying and pasting within my component:
import React, { Component } from 'react';
import { makeStyles } from '#material-ui/core/styles';
import InputLabel from '#material-ui/core/InputLabel';
import MenuItem from '#material-ui/core/MenuItem';
import FormHelperText from '#material-ui/core/FormHelperText';
import FormControl from '#material-ui/core/FormControl';
import Select from '#material-ui/core/Select';
export class Survey extends Component {
state = {
}
const useStyles = makeStyles((theme) => ({
formControl: {
margin: theme.spacing(1),
minWidth: 120,
},
selectEmpty: {
marginTop: theme.spacing(2),
},
}));
export default function SimpleSelect() {
const classes = useStyles();
const [age, setAge] = React.useState('');
const handleChange = (event) => {
setAge(event.target.value);
};
}
render() {
return (
<React.Fragment>
<h2>Survey Start</h2>
<FormControl className={classes.formControl}>
<InputLabel id="demo-simple-select-helper-label">Age</InputLabel>
<Select
labelId="demo-simple-select-helper-label"
id="demo-simple-select-helper"
value={age}
onChange={handleChange}
>
<MenuItem value="">
<em>None</em>
</MenuItem>
<MenuItem value={10}>Ten</MenuItem>
<MenuItem value={20}>Twenty</MenuItem>
<MenuItem value={30}>Thirty</MenuItem>
</Select>
<FormHelperText>Some important helper text</FormHelperText>
</FormControl>
</React.Fragment>
);
}
}
However this returned several errors, including citing the line where I defined useStyles:
The 'const' modifier can only be used in Type Script files.
Not sure why it threw that since I was careful to click the javascript example file on the example source code.
Question
How do I get the materialUI example user select to integrate with a vanilla component?
You are mixing components inside components.
Try to see thinking in react to get a better understanding of how component works. You need to export <SimpleSelect /> as its own component, then use it in your <Survey /> component.
Refactored code:
import React, { Component } from 'react';
import { makeStyles } from '#material-ui/core/styles';
import InputLabel from '#material-ui/core/InputLabel';
import MenuItem from '#material-ui/core/MenuItem';
import FormHelperText from '#material-ui/core/FormHelperText';
import FormControl from '#material-ui/core/FormControl';
import Select from '#material-ui/core/Select';
const useStyles = makeStyles(theme => ({
formControl: {
margin: theme.spacing(1),
minWidth: 120
},
selectEmpty: {
marginTop: theme.spacing(2)
}
}));
function SimpleSelect() {
const classes = useStyles();
const [age, setAge] = React.useState('');
const handleChange = event => {
setAge(event.target.value);
};
return (
<FormControl className={classes.formControl}>
<InputLabel id="demo-simple-select-helper-label">Age</InputLabel>
<Select
labelId="demo-simple-select-helper-label"
id="demo-simple-select-helper"
value={age}
onChange={handleChange}
>
<MenuItem value="">
<em>None</em>
</MenuItem>
<MenuItem value={10}>Ten</MenuItem>
<MenuItem value={20}>Twenty</MenuItem>
<MenuItem value={30}>Thirty</MenuItem>
</Select>
<FormHelperText>Some important helper text</FormHelperText>
</FormControl>
);
}
export class Survey extends Component {
state = {};
render() {
return (
<>
<h2>Survey Start</h2>
<SimpleSelect />
</>
);
}
}
Related
Ive downloaded a DarkModeToggle npm for my react app however I am a bit confused as to actually add the functionallity. Currently the button lets me click it on the appbar and the button itself changes however the state of my app does not.
import React, { useState, useEffect } from "react";
import { Container, AppBar, Typography, Grow, Grid } from "#material-ui/core";
import { useDispatch } from "react-redux";
import DarkModeToggle from "react-dark-mode-toggle";
// import { getPosts } from './actions/posts'
import Posts from "./components/Posts/Posts";
import Form from "./components/Form/Form";
import wisp_logo from "./images/wisp_logo.png";
import useStyles from "./styles";
const App = () => {
const [currentId, setCurrentId] = useState();
const classes = useStyles();
const dispatch = useDispatch();
const [isDarkMode, setIsDarkMode] = useState(() => false);
return (
<Container maxwidth="lg">
<AppBar className={classes.appBar} position="static" color="inherit">
<DarkModeToggle
onChange={setIsDarkMode}
checked={isDarkMode}
size={80}
/>
</AppBar>
</Container>
);
};
export default App;
If you wish to customize the theme, you need to use the ThemeProvider component in order to inject a theme into your application. Here's a simple example:
Custom variables:
const darkTheme = createTheme({
palette: {
type: "dark"
}
});
Use the ThemeProvider component:
<ThemeProvider theme={darkTheme}>
<AppBar
position="static"
color={`${isDarkMode ? "default" : "primary"}`}
>
<DarkModeToggle
onChange={setIsDarkMode}
checked={isDarkMode}
size={80}
/>
</AppBar>
</ThemeProvider>
Using a ternary to change the theme:
color={`${isDarkMode ? "default" : "primary"}`}
Exemplo completo aqui: https://codesandbox.io/s/holy-wood-cdgpks?file=/src/App.js
I believe there are 2 things to change:
The first one is that "isDarkMode" is a boolean, and inside the useState you're using a function, so must be like this:
const [isDarkMode, setIsDarkMode] = useState(false);
Also, when sending the "setIsDarkMode" function you need to update your state, like this:
<DarkModeToggle
onChange={() => setIsDarkMode(prevState => !prevState)}
checked={isDarkMode}
size={80}
/>
So "onChange" is now a function that is going to update the state on every click
I have created a theme in the index of my React.JS project using MUI. When I try to apply my style to my Appbar the theme does not correctly modify the menu button nor the menu itself. the button looks generic default and the menu remains white when it should match the color of the Appbar itself.
My index.tsx looks as such:
import React from "react";
import ReactDOM from "react-dom";
import AppbarTop from "./AppbarTop";
import { Router } from "react-router";
import { createBrowserHistory } from "history";
import AdapterDateFns from "#mui/lab/AdapterDateFns";
import { LocalizationProvider } from "#mui/lab";
import { createTheme } from "#mui/material";
import { ThemeProvider } from "#mui/styles";
import { StyledEngineProvider } from "#mui/material/styles";
const customHistory = createBrowserHistory();
const theme = createTheme({
palette: {
primary: {
main: "#242526"
},
secondary: {
main: "#d975d0"
},
text: {
primary: "#E4E6EB",
secondary: "#B0B3B8"
},
background: {
default: "#242526",
paper: "#242526"
}
}
});
ReactDOM.render(
<React.StrictMode>
<LocalizationProvider dateAdapter={AdapterDateFns}>
<Router history={customHistory}>
<ThemeProvider theme={theme}>
<StyledEngineProvider injectFirst>
<AppbarTop />
</StyledEngineProvider>
</ThemeProvider>
</Router>
</LocalizationProvider>
</React.StrictMode>,
document.getElementById("root")
);
My appbar.tsx looks like this:
import React from "react";
import {
AppBar,
Box,
Button,
Container,
Menu,
MenuItem,
Toolbar
} from "#mui/material";
import HomeIcon from "#mui/icons-material/Home";
import { makeStyles } from "#mui/styles";
const useStyles = makeStyles((theme?: any) => ({
appBar: {
background: theme.palette.primary.main,
height: "60px",
position: "relative"
}
}));
const AppbarTop: React.FC<{ [key: string]: any }> = () => {
const classes = useStyles();
const [anchorEl, setAnchorEl] = React.useState<any>(null);
const open = Boolean(anchorEl);
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
return (
<>
<AppBar position="static" className={classes.appBar}>
<Toolbar>
<Button
id="basic-button"
aria-controls="basic-menu"
aria-haspopup="true"
aria-expanded={open ? "true" : undefined}
onClick={handleClick}
>
Dashboard
</Button>
<Menu
id="basic-menu"
anchorEl={anchorEl}
open={open}
onClose={handleClose}
MenuListProps={{
"aria-labelledby": "basic-button"
}}
>
<MenuItem onClick={handleClose}>
<HomeIcon />{" "}
</MenuItem>
</Menu>
{/*test speed dial*/}
<Container maxWidth="sm"></Container>
<Box></Box>
</Toolbar>
</AppBar>
</>
);
};
export default AppbarTop;
Can someone please explain what I am missing?
Change this line:
import { ThemeProvider } from "#mui/styles";
To:
import { ThemeProvider } from "#mui/material/styles";
Reason: There are 2 ThemeProviders here
The one from #mui/styles: This ThemeProvider does send the Theme object down via context, it works fine, you can still access it using the useTheme hook:
const theme = useTheme();
return <Box sx={{ width: 10, height: 10, bgcolor: theme.palette.primary.main }} />
The one from #mui/material/styles: This ThemeProvider is a wrapper of the above, but it also injects the theme to the StyledEngineThemeContext.Provider, which allows you to access the theme when using MUI API (sx prop/styled()). The problem here is that the Button and Menu components uses the styled() API under-the-hood so the ThemeProvider needs to be imported from #mui/material/styles to make it work.
return <Box sx={{ width: 10, height: 10, bgcolor: 'primary.main' }} />
Related answers
Difference between #mui/material/styles and #mui/styles?
Cannot use palette colors from MUI theme
MUI - makeStyles - Cannot read properties of undefined
Material UI Dark Mode
I'm facing issue with follow DraftJS editor component.
import React, { useRef } from "react";
import styled from "styled-components";
import { EditorState, Editor as DraftEdior } from "draft-js";
const Wrapper = styled.div`
border: 1px solid #ccc;
padding: 1rem;
`;
interface IEditorProps {
state: EditorState;
onChange: (state: EditorState) => void;
readOnly?: boolean;
}
export const Editor: React.FunctionComponent<IEditorProps> = (props) => {
const { state, onChange, readOnly } = props;
const ref = useRef<DraftEdior | null>(null);
return (
<Wrapper onClick={() => ref?.current?.focus()}>
<DraftEdior
ref={ref}
editorState={state}
onChange={onChange}
readOnly={!!readOnly}
/>
</Wrapper>
);
};
export default Editor;
and the App.js
import React from "react";
import { EditorState } from "draft-js";
import { Editor } from "./Editor";
const App = () => {
const [state, setState] = React.useState<EditorState>(() =>
EditorState.createEmpty()
);
return (
<>
<h3>Editor</h3>
<Editor state={state} onChange={(state) => setState(state)} />
<h3>Result</h3>
<Editor state={state} readOnly onChange={() => null} />
</>
);
};
export default App;
When only a single editor on the page, everything work ok. But the editor continuously lost focus when I add a readonly component.
This is a code sanbox link
https://codesandbox.io/s/vigilant-wilson-70op8?file=/src/App.tsx:0-451
How to fix it, thank you very much.
I'd like to supply a material UI TextField component to the PhoneInput component from react-phone-number-input as the inputComponent prop.
However, I don't seem to be able to successfully apply the ref. Although I see the Material UI TextField component rendered to the UI and state is successfully updated with the value, it keeps loosing focus after the first value has been typed.
import React, { forwardRef, createRef } from 'react';
import { TextField } from '#material-ui/core';
import 'react-phone-number-input/style.css';
import PhoneInput from 'react-phone-number-input';
const SampleComponent = ({ handleChange }) => {
const phoneInput = forwardRef((props, ref) => {
return (
<TextField
inputRef={ref}
fullWidth
label="Phone Number"
variant="outlined"
name="phone"
onChange={handleChange}
/>
);
});
const ref = createRef();
return (
<PhoneInput ref={ref} inputComponent={phoneInput} />
);
};
So I was able to get it to work using the following method. Any suggestions on how to improve this are more than welcome.
I have a separate file called PhoneNumber.jsx
import { forwardRef } from 'react'
import TextField from '#material-ui/core/TextField'
import { makeStyles } from '#material-ui/core/styles'
const useStyles = makeStyles(theme => ({
input: {
backgroundColor: '#fff'
}
}))
const phoneInput = (props, ref) => {
const classes = useStyles()
return (
<TextField
{...props}
InputProps={{
className: classes.input
}}
inputRef={ref}
fullWidth
size='small'
label='Phone Number'
variant='outlined'
name='phone'
/>
)
}
export default forwardRef(phoneInput)
And my form file:
import PhoneInput from 'react-phone-number-input'
import CustomPhoneNumber from '../components/prebuilt/PhoneNumber'
...
<PhoneInput
placeholder='Enter phone number'
value={phone}
onChange={setPhone}
inputComponent={CustomPhoneNumber}
/>
...
There is also a package for Material UI v5 (or MUI) called Mui tel input and it's working with React 17 and 18 !
Simply way to use. Phone validation available too.
Check the doc here : https://github.com/viclafouch/mui-tel-input
import React from 'react'
import { MuiTelInput } from 'mui-tel-input'
const MyComponent = () => {
const [value, setValue] = React.useState('')
const handleChange = (newValue) => {
setValue(newValue)
}
return <MuiTelInput label="Phone" fullWidth value={value} onChange={handleChange} />
}
I wonder why <FormControl /> does not accept the prop variant. According to the docs, this prop is available.
import React from "react";
import { render } from "react-dom";
import FormControl from "#material-ui/core/FormControl";
import Select from "#material-ui/core/Select";
import MenuItem from "#material-ui/core/MenuItem";
const App = () => {
return (
<div>
<FormControl variant="outlined">
<Select value="foo" onChange={() => {}} autoWidth={true}>
<MenuItem value="foo">Kitten</MenuItem>
<MenuItem value="bar">Puppy</MenuItem>
</Select>
</FormControl>
</div>
);
};
render(<App />, document.getElementById("root"));
However, it does not work. Here is a Sandbox reproducing the problem.
https://codesandbox.io/s/material-ui-9ut2q
import React, { useState } from "react";
import { render } from "react-dom";
import FormControl from "#material-ui/core/FormControl";
import Select from "#material-ui/core/Select";
import MenuItem from "#material-ui/core/MenuItem";
const App = () => {
const [state, setValues] = useState({
defaults: "foo"
});
const changeValue = e => {
setValues({ ...state, defaults: e.target.value });
};
return (
<div>
<FormControl variant="outlined">
<Select
value={state.defaults}
onChange={e => {
changeValue(e);
}}
autoWidth={true}
>
<MenuItem value="foo">Kitten</MenuItem>
<MenuItem value="bar">Puppy</MenuItem>
</Select>
</FormControl>
</div>
);
};
render(<App />, document.getElementById("root"));
package.json
{
"dependencies": {
"react": "^16.7.0-alpha.2",
"react-dom": "^16.7.0-alpha.2",
...
},
https://codesandbox.io/s/material-ui-ksggx?fontsize=14
try this it will work