How to style components properly in React - reactjs

I have the following component Login. What it does is not important but for the styling, you can see inside the render, I added loginStyle, columnStyle, and inputStyle. This works fine but I have another component Register pretty much identical to the Login component with just a few changes, which are not important. But in my Register component I have the same thing columnStyle, inputStyle, and instead of loginStyle I have registerStyle.
The styles I am applying in Login and Register are exactly the same. My question is do I create some sort of component that has all these stylings I created (and just create them once to not have duplicate code) and somehow use that to style anything that needs styling in different components or do I just keep a separate js file that contains all these styles and import it into separate component files. I just want to know the professionally accepted way for this. I am aware that we can use css but I see a lot of projects not using css to style their components.
import React from 'react';
import Button from '../Buttons/Button';
class Login extends React.Component {
constructor(props) {
super(props);
this.state = {
email: '',
password: '',
};
this.onChange = this.onChange.bind(this);
this.onSubmit = this.onSubmit.bind(this);
}
onChange(event) {
this.setState({
[event.target.name]: event.target.value,
});
}
onSubmit(event) {
event.preventDefault();
alert('Login button clicked');
}
render() {
const loginStyle = {
display: 'flex',
flexDirection: 'row',
rowGap: '15px',
};
const columnStyle = {
display: 'flex',
flexDirection: 'column',
width: '100vw',
rowGap: '30px',
};
const inputStyle = {
fontSize: '40px',
outline: 'none',
border: 'none',
borderBottom: '1px solid black',
};
return (
<form onSubmit={this.onSubmit} style={loginStyle}>
<div style={columnStyle}>
<input
style={inputStyle}
placeholder='Enter your email...'
type='email'
name='email'
value={this.state.email}
onChange={this.onChange}
/>
<input
style={inputStyle}
placeholder='Enter your password...'
type='password'
name='password'
value={this.state.password}
onChange={this.onChange}
/>
<Button type='submit' />
</div>
</form>
);
}
}
export default Login;

The projects you refer to is most likely small ones. Using styling in this way is not scalable. Surely still a valid choice, as react native for example is better styled this way, or even small UI library alike components in projects. But in general, use css and smack preprocessor on top of that for even further enhancing development experience.
Then look up good rule set for your css, as an example Airbnb provides good things regarding this https://github.com/airbnb/css
This can be from simple names you use for classes, to file structure.

Is better approach for each component to make a .css file or modules.css file, this technique will help you to keep your style seperate from your component and you can make it responsive easier.
If your example have same style-css for two or three components or divs you can make this style global and use it in your every js file.
Most of the elements have className attribute that you can write your styles by name it for example
<div className="columnStyle">
<input
className="inputStyle"
placeholder='Enter your email...'
type='email'
name='email'
value={this.state.email}
onChange={this.onChange}
/>
</div>
and in your .css file you can add the styling
.columnStyle {
display: 'flex',
flexDirection: 'column',
width: '100vw',
rowGap: '30px',
};
.inputStyle {
fontSize: '40px',
outline: 'none',
border: 'none',
borderBottom: '1px solid black',
};

Related

Multiple InputBase fields sharing a single InputLabel using FormControl: How (without warning)

I'm building a custom form widget where multiple fields need to share a single label. I need the label to highlight when any of the fields are focused.
Here's a codesandbox, or if you prefer, here's a snippet of the relevant code:
const MyInputBase = styled(InputBase)(({ theme }) => ({
"label + &": {
marginTop: theme.spacing(3)
},
"& .MuiInputBase-input": {
backgroundColor: theme.palette.mode === "light" ? "#fcfcfb" : "#2b2b2b",
border: "1px solid #ced4da",
padding: "10px 12px",
"&:focus": {
backgroundColor: "rgba(63, 127, 63, 0.1)"
}
}
}));
const MyInputLabel = styled(InputLabel)(({ theme }) => ({
"&.Mui-focused": {
color: "rgb(63, 175, 63)"
}
}));
const MyAdornment = ({ children }: { children: React.ReactNode }) => {
return (
<InputAdornment position={"start"}>
<Typography
sx={{
fontSize: "12px",
color: "rgb(83, 127, 83)"
}}
>
{children}
</Typography>
</InputAdornment>
);
};
export default function InputsThatShareALabel() {
return (
<Box component="form" noValidate>
<FormControl variant="standard">
<MyInputLabel shrink>Medalists</MyInputLabel>
<MyInputBase startAdornment={<MyAdornment>1ST</MyAdornment>} />
<MyInputBase startAdornment={<MyAdornment>2ND</MyAdornment>} />
<MyInputBase startAdornment={<MyAdornment>3RD</MyAdornment>} />
</FormControl>
</Box>
);
}
Everything works as intended but I have the error:
There are multiple `InputBase` components inside a FormControl.
This creates visual inconsistencies, only use one `InputBase`.
I understand the rationale behind the error, and that this is not the intended usage of FormControl. I have read this related Github issue and this related Github issue, etc. I think the difference is that I'm manually managing the differences in appearance for each field in the group, so I'm not depending on FormControl for that, just taking advantage of the InputLabel's already extant highlight/focus context usage.
I've also taken a look at this similar StackOverflow question, but it doesn't seem to quite address my concern.
I think what MUI refers to as "visual inconsistencies" is actually my desired behavior. I have handrolled my own label-highlighting logic for now, but was wondering if a MUI "way" has emerged to allow this without a warning.

Editing the font color of the text inside ImageListItemBar

I'm new to using Material UI and have integrated into my portfolio website to create an ImageList that redirect to other projects I'd like to show possible employers. I'm having trouble editing the style of the text inside ImageListItemBar. I've tried using the primaryTypographyProps and sx to no avail. Could someone point me in the right direction?
<Typography variant="h3" color="common.red">
<ImageListItemBar
primaryTypographyProps={{fontSize: '30px'}}
sx={{
background: 'black',
}}
position="bottom"
title={item.title}
/>
</Typography>
//tried this as well
<ImageListItemBar
sx={{
color: '#000';
background: 'black',
}}
position="bottom"
title={item.title}
/>
Here is the code You are after:
<ImageListItemBar
title="image title"
subtitle="image subtitle"
sx={{
"& .MuiImageListItemBar-title": { color: "red" }, //styles for title
"& .MuiImageListItemBar-subtitle": { color: "yellow" }, //styles for subtitle
}}
/>
I recommend studying official MUI docs for ImageList and ImageListItemBar API
Hamed's answer is correct, you need to target the specific class applied to the title in order to style it.
I've been developing a pattern of doing this lately, where you can import the component's classes and style accordingly using styled. This allows you to use your IDE to autocomplete the class names and target them accordingly.
const StyledImageListItemBar = styled(ImageListItemBar)(() => ({
[`& .${imageListItemBarClasses.title}`]: {
color: "red"
},
[`& .${imageListItemBarClasses.subtitle}`]: {
color: "yellow"
},
backgroundColor: "black"
}));
Then you can just use the component without having to resort to sx:
export default function App() {
return (
<StyledImageListItemBar
title="This is a title"
subtitle="This is a subtitle"
/>
);
}
Here's a sandbox of this in action if you want to play with it: https://codesandbox.io/s/mui-targetting-classes-8y5kpm?file=/src/App.js
That being said, if you're planning to reuse this component with the custom styling, I would consider overriding the default styling in theme too.

How do I set a width for the TextAreaAutoSize component in Material-UI?

I can't find any info anywhere on how to change the default width of a TextAreaAutosize component in material-ui.
It seems the only choice is to have this little box. Does anyone know of a better text area auto size component I can use, or how to change the width of the TextAreaAutoSize component?
The API doesn't show any properties that have anything to do with 'className'. I tried to use it anyway and it was ignored. I also tried wrapping the component in a Box, and styling that, but it was ignored by the TextArea.
Any help would be greatly appreciated!
Resizing by the user is turned off (via resize: "none") for TextField here in InputBase: https://github.com/mui-org/material-ui/blob/v4.10.2/packages/material-ui/src/InputBase/InputBase.js#L140.
Below is an example of how to turn it back on:
import React from "react";
import { makeStyles } from "#material-ui/core/styles";
import TextField from "#material-ui/core/TextField";
const useStyles = makeStyles(theme => ({
root: {
"& .MuiTextField-root": {
margin: theme.spacing(1)
}
},
textarea: {
resize: "both"
}
}));
export default function MultilineTextFields() {
const classes = useStyles();
return (
<form className={classes.root} noValidate autoComplete="off">
<div>
<TextField
id="outlined-textarea"
label="Multiline Placeholder"
placeholder="Placeholder"
multiline
variant="outlined"
inputProps={{ className: classes.textarea }}
/>
</div>
</form>
);
}
CSS documentation for resize: https://developer.mozilla.org/en-US/docs/Web/CSS/resize
Multiline TextField demos: https://material-ui.com/components/text-fields/#multiline
You can change the style prop of the TextareaAutosize check here
<TextareaAutosize
rowsMin={3}
placeholder=''
defaultValue=''
style={{ width: "100%" }}
/>
I was able to get it to work thanks to Ryan Cogswell. Stupid me, though I wrapped the textarea in a box and applied className to the box (which didn't work), I should have applied it to the textareaautosize directly.
There's a bug in VSCODE Intellisense where it shows 'classes' as a property but not 'className' so I assumed it didn't exist.
Here's the code:
const FormStyles = makeStyles((theme) => ({
root: {
width: '100%',
},
button: {
marginTop: '20px',
marginRight: theme.spacing(1),
},
buttons: {
display: 'flex',
justifyContent: 'flex-end'
},
textarea: {
width: '100%',
},
}));
<TextareaAutosize
rowsMin={3}
aria-label={info.label}
name={info.name}
placeholder=''
defaultValue=''
className={classes.textarea}
/>
I could not get the drag icon to show up in textfield, so didn't use it. But I would appreciate an example of textfield using multiline and resizing.
Thanks Ryan!
Here's the trick I used. I wrapped it in a flex container and used align-items to stretch the width to cover the size of that container.
<Stack
direction="column"
justifyContent="center"
alignItems="stretch"
spacing={2}
>
<TextareaAutosize
label='Title'
value={pub.title || ''}
onChange={(e) => pub.title = e.target.value}
variant='outlined'
sx={{m: 1}}
size='small'
/>
</Stack>

How to put border bottom to react-chips in reactjs?

I'm new to react and I have created a modal and used react-chips for showing suggestions, but I wasn't able to change the field styling the same way I changed it for the subject input field. I've tried styling but I'm unable to change the styling of the react-chip.
Here is the code:
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
chips: []
};
}
onChange = chips => {
this.setState({ chips });
};
render() {
return (
<Container>
<Modal trigger={<Button>Show Modal</Button>}>
<Modal.Content>
<Form>
<strong>Email</strong>
<Chips
className="f_input"
value={this.state.chips}
onChange={this.onChange}
suggestions={["Your", "Data", "Here"]}
/>
<Form.Field
transparent
className="f_input"
control={Input}
label="Subject"
/>
<TextArea placeholder="Email Format" />
</Form>
<Button>Send</Button>
</Modal.Content>
</Modal>
</Container>
);
}
}
Here is the Code: https://codesandbox.io/s/boring-yalow-sx678
Can anyone help me in this query?
The library encourages styling the chips using the chipTheme prop;
Here is for example how you can add some custom styling to the chips in the example you provided:
<Chips
className="f_input"
value={this.state.chips}
onChange={this.onChange}
suggestions={["Your", "Data", "Here"]}
chipTheme={{
chip: {
color: "white",
background: "blue",
borderRadius: 20
},
chipRemove: {
fontWeight: "bold",
cursor: "pointer",
color: "green",
":hover": {
color: "yellow"
}
}
}}
/>
UPDATE
In case you would like to style the chips-container and input you should use the theme prop.
In your case you should override the chipsContainer style with the following properties in order to get an underline similar to the one you have on the "subject" input :
border: "none",
borderBottom: "1px solid black",
marginBottom: 14,
Here is your forked sandbox with the solution.
And here is a reference to the default theme objects which you can override.

How can i make an avatar chooser with Material UI

I'm using Material UI v3 within a react project (react v15.6).
What i did so far?
In the sign up page i can get an image from the user to use as his/her profile photo.
What i want to do
I would like to have a shade on the avatar photo to show him that is clickable. like this image...
avatarChooserImage
Someone can tell me, how can i do such a thing? I have no clue. I tried to use plain CSS, but much effort for nothing.
You can do something simple like this,
<IconButton>
<Avatar
src="/images/example.jpg"
style={{
margin: "10px",
width: "60px",
height: "60px",
}}
/>
</IconButton>
Which allow you to have a clickable avatar.
But since you are using it as file input too, maybe you can do something like this,
<input
accept="image/*"
className={classes.input}
id="contained-button-file"
multiple
type="file"
/>
<label htmlFor="contained-button-file">
<IconButton>
<Avatar
src="/images/example.jpg"
style={{
margin: "10px",
width: "60px",
height: "60px",
}}
/>
</IconButton>
</label>
To do an overlay for "edit", have a look at css image overlay. This explains how to place a layer on top on Avatar Icon, it should answer you question.
P.S Accept this as the right answer if it answers your question, thank you.
There's a similar example of this in the documentation:
https://material-ui.com/components/buttons/#upload-button
Instead of using "PhotoCamera" , you can use "Avatar". Allowing you to click on your avatar to upload an image like this for example:
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import Avatar from '#material-ui/core/Avatar';
import IconButton from '#material-ui/core/IconButton';
const useStyles = makeStyles((theme) => ({
root: {
alignSelf: 'center',
justifyContent: "center",
alignItems: "center",
display: 'flex',
'& > *': {
margin: theme.spacing(1),
},
},
input: {
display: "none",
},
large: {
width: theme.spacing(7),
height: theme.spacing(7),
},
}));
export default function ProfileAvatar() {
const classes = useStyles();
return (
<div className={classes.root}>
<input accept="image/*" className={classes.input} id="icon-button-file" type="file" />
<label htmlFor="icon-button-file">
<IconButton color="primary" aria-label="upload picture" component="span">
<Avatar src="https://www.w3schools.com/howto/img_avatar.png" className={classes.large} />
</IconButton>
</label>
</div>
);
}
An hidden input that accepts images only,
and an IconButton with component="span" property, surrounded by the input's label:
<input accept="image/*" id="upload-avatar-pic" type="file" hidden />
<label htmlFor="upload-avatar-pic">
<IconButton component="span">
<Avatar />
</IconButton>
</label>

Resources