How to make a React component reusable in terms of styling? - javascript

Consider the following input component with its own scss file:
import React from "react";
import "./InputBox.scss";
const InputBox = () => {
return (
<div>
<label for="fname">First name: </label>
<input className="input-box" type="text" id="fname" name="fname" />
</div>
);
};
export default InputBox;
.input-box {
background-color: blue;
}
import React from "react";
import InputBox from "./InputBox";
export default function App() {
return (
<div className="App">
<div>The blue input box</div>
<InputBox />
<div>The green input box</div>
<InputBox />
</div>
);
}
Working example here
The functionality is okay, my question is with the styling: say I want a green input box, it doesn't seem possible with the external SCSS file. I can pass a className as a props but I feel it's a overkill. I feel my component should not contain any style, and only apply style when using it. How can I style the same component differently?

depending on the project I usually pass a variant prop which will determine the element's styling, so for example you have a default styling for an input field but you do have so different variants of the input with its own unique styling. So all you can do is pass a variant which will add a modifier block to your class name.
default classname = 'input'
depending on the variant the entire class name should be something like 'input input--variant-name'
all default styling go to the 'input' class name while the variant makes the changes. I feel it isn't an overkill as it is much more organized this way and with a use of a scss and css variables together you make have a very organized project structure for your styling.

you can do it by using useRef hook,here is the live demo link:https://codesandbox.io/s/romantic-ride-j0hdp?file=/src/App.js
this way you wont be requiring any css file.

I tried to pass className as a prop and it worked, code here:
const InputBox = ({ color }) => {
return (
<div>
<label for="fname">First name: </label>
<input
className={"input-box-" + color}
type="text"
id="fname"
name="fname"
/>
</div>
);
};
.input-box {
&-blue {
background-color: blue;
}
&-green {
background-color: green;
}
}
export default function App() {
return (
<div className="App">
<div>The blue input box</div>
<InputBox color={"blue"} />
<div>The green input box</div>
<InputBox color={"green"} />
</div>
);
}
I can see a few problems already:
When design a component, should I consider all possible style changes and design them as props? If yes, then every time using the component requires writing all props, which is cumbersome. If no, adding a prop requires modifying the component.

Related

React Button Click should change the display value of div

I got a Navbar which has a button do change the display value of a login form. The Login form and the Login form is a diffrent file, the navbar is a diffrent file and the homepage where it should be display is a diffrent file. Those are the minimal variants of each so that you got some got to understand my problem in detail:
Homepage:
const HomePage = () => {
return (
<div>
<Navbar />
<Login />
<div id="content">
</div>
</div>
);
}
Navbar:
const Navbar= () => {
const showLogin = () => {
document.getElementById('Login').style.display='block';
}
return (
<div id="Navbar">
<NavLink activeClassName="active" to='/'><img src={logo}/></NavLink>
<ul>
...
</ul>
<ul>
<button onClick={showLogin}>Anmelden</button>
</ul>
</div>
);
}
Login-Form:
const Login = () => {
return (
<div id="Login">
<form>
<label>Anmelden</label>
<label for="username">Nutzername</label>
<input name="username" type="text"></input>
<label for="pw">Passwort</label>
<input name="pw" type="password"></input>
<button type="submit">Login</button>
</form>
</div>
);
}
Is there a way to achieve this, or would my easiest option be to include the Login source code into the Navbar source code?
You do not need to move your Login component inside Navbar. Keep it as it is.
You can use useState and Props to switch css classes to show/hide your Login component. I have created very simple solution for you in this CodeSandbox.
Steps:
Create two CSS classes hidden and block
In your Login component add a boolean prop which switches class hidden to block if true.
Create a prop for onClick in the Login component.
Create a useState inside your Homepage which holds a boolean value. That boolean value pass it to the Login page prop and then use onClick prop from Navbar to switch that boolean state
Yes, depending on your CSS system this is easily achievable just by using that.
The React solution is using refs.
The easy way is to create a ref in the parent component and then pass it down as a prop to both components:
In Homepage (i.e. parent), create a ref like so loginRef = useRef(); then pass it down as a prop to the 2 children.
In Login-Form.js you assign that prop on the div with id Login like so <div id='Login' ref={props.loginRef}>
Then in Navbar.js you can use that prop to change its display value like so const showLogin = () => {props.loginRef.current.style.display='block';}
NB: This is a fast and easy way, not best practice but it gets the work done. The best-practice here is to use forwardRef and - super advanced - useImperativeHandle. Take your time and go through the documentation when you're ready.
Login page will show "it is not active" first because active is set to false.but once you click on submit button it will show "it is active"
HomePage
const HomePage = () => {
const[active,setActive]=useState(false);
return (
<div>
<Navbar activesetter={setActive} />
<Login activestatus={active} />
<div id="content">
</div>
</div>
);
}
Login
const Login = (props) => {
return(
<div>
<div>
{props.activestatus ? "it is active" : "it is not active" }
</div>
</div>
);
}
Navbar
const Navbar = (props) => {
const handleSubmit=(e)=> {
e.preventDefault();
props.activesetter(true);
}
return(
<div>
<form onSubmit={handleSubmit}>
<button type="submit">Login</button>
</form>
</div>
);
}

Different colors for different h1 titles in differents components with React

I'm trying to get different colors for different titles in different components with a React application.
I dispatched the css into two different css files but the h1 color which is applied is the same (the last value read) for both h1 titles.
// App.js
import React from "react";
import ComponentOne from "./ComponentOne.component";
import ComponentTwo from "./ComponentTwo.component";
import "./styles.css";
export default function App() {
return (
<div className="App">
<ComponentOne />
<ComponentTwo />
</div>
);
}
// ComponentOne.module.css
h1 {
color: red;
}
// ComponentTwo.module.css
h1 {
color: blue;
}
In each component I have the corresponding CSS import line:
import "./ComponentOne.module.css";
Can you help me figuring out what is going wrong with my code please ?
The "module" naming convention I used for the CSS files is adapted from this, while the whole code can be found here.
Thanks a lot.
The reason it only picks blue is because the browser does not care about what css is in what file, it will just read it all, and if there is already a style for a h1 and then it finds a different style for a h1 it will simply overwrite the previous style.
In your case the red color gets overwritten, and instead all the h1 become blue
This is why its very bad practice to just overwrite all instances of a specific element type. instead what you should do is wrap your code in a div/span with some id/class like this:
<div id="section1">
<h1>i am blue</h1>
</div>
<div id="section2">
<h1>i am red</h1>
</div>
and then instead of styling all the h1's everywhere on the page, you could style all the h1's that are contained in an element with some id. you can do that like this
#section1 > h1 {
color: blue;
}
#section2 > h1 {
color: red;
}
There is one issue in that when you use css module you need to import those classes and need to use it there. You can't use it on tag or elements. For that you need to use styled-component or any similar library.
IN your case you need to like this:
<div>
<h1 className={styles.heading}>Component One</h1>
</div>
where heading is your class name.
Full code:
ComponentOne.component.js
import React, { Component } from "react";
import styles from "./ComponentOne.module.css";
export default class ComponentOne extends Component {
render() {
return (
<div>
<h1 className={styles.heading}>Component One</h1>
</div>
);
}
}
ComponentOne.module.css
.heading {
color: red;
}
ComponentTwo.component.js
import React, { Component } from "react";
import styles from "./ComponentTwo.module.css";
export default class ComponentTwo extends Component {
render() {
return (
<div>
<h1 className={styles.heading}>Component Two</h1>
</div>
);
}
}
ComponentTwo.module.css
.heading {
color: red;
}
Code and demo can be found here: https://codesandbox.io/s/elated-dream-2ocmf?file=/src/ComponentOne.component.js
I believe that without an extra pre-processor JavaScript won't scope your CSS files to specific components. It will just include both files to the app CSS output. And because the second and last loaded module was setting the colour to blue, it overrides the first one.
You will need to identify both components by a class or an ID so you can apply the styles conditionally.
Use className instead. Since <componentTwo /> gets rendered least it's styling will dominate.
add in-line styling for example:
<div>
<h1 style={{color:"red"}}>Component Two</h1>
</div>
or you can also programatically change the styling
render() {
var color = "blue";
var foo = "bar"
if(foo == "bar"){
color="red"
}
return (
<div>
<h1 style={{color:color}}>Component Two</h1>
</div>
);
}

how to change label color when input field is focus in react js

could you please tell me how to change label color when the input field is focused in react js I am using semantic UI
https://react.semantic-ui.com/collections/form/#types-form
here is my code
<Form>
<Form.Field>
<label>First Name</label>
<input placeholder="First Name" />
</Form.Field>
<Form.Field>
<Checkbox label="I agree to the Terms and Conditions" />
</Form.Field>
<Button type="submit">Submit</Button>
</Form>
https://codesandbox.io/s/semantic-ui-react-example-i6crv
You can actually use :focus-within selector of CSS to easily apply CSS.
div:focus-within applies CSS when any element is focussed inside your div. In your case, you can give a class to your input group — let's say input-group. And then use .input-group:focus-within label selector to style your label.
Check out the working code sandbox demo of your code.
All I did is added the following stylesheet and it worked.
.input-group:focus-within label {
color: red !important;
}
You can use react hooks (useState) to change color of the label:
Working Fork - https://codesandbox.io/s/semantic-ui-react-example-fwiz4
Just rewrite the component, include useState, and then use onFocus event inside the input field. Once it is focused, state hook will modify the focused state to true, which you can use to apply custom style or class. If you have more field, just add more state params, instead of one (focused in this example).
import React, {useState} from "react";
import { Button, Checkbox, Form } from "semantic-ui-react";
const FormExampleForm = () => {
const [focused, setFocused] = useState(false); // set false as initial value
return(
<Form>
<Form.Field>
<label style={{color: focused ? 'red' : ''}}>First Name</label>
<input placeholder="First Name" onFocus={() => setFocused(true)} />
</Form.Field>
<Form.Field>
<Checkbox label="I agree to the Terms and Conditions" />
</Form.Field>
<Button type="submit">Submit</Button>
</Form>
);
}
export default FormExampleForm;

React input focus event to display other component

I was read some tutorial about this. They told me should using ref to do that.
But It's very general.
Here is my problem:
Basically in Header component include NavBar, SearchBar and ResultSearch component.
const Header = () => {
return (
<header className="ss_header">
<Navbar />
<SearchBar />
<ResultSearch />
</header>
);
};
And In SearchBar component. Whenever I focused on input text. It emit an event and display ResultSearch component by any way (changing style, or ...).
class SearchBar extends Component{
render() {
return (
<div className="search_bar">
<section className="search">
<div className="sub_media container">
<form method="GET" action="" id="search_form">
<Icon icon="search" />
<span className="autocomplete">
<input
className="search_input"
autoCorrect="off"
autoComplete="off"
name="query"
type="text"
placeholder="Search for a movie, tv show, person..." />
</span>
</form>
</div>
</section>
</div>
);
}
}
Style in ResultSearch component. I was set display: none.
.results_search { display: none; }
I think ResultSearch will receive an event from SearchBar and set back display: block for ResultSearch component. Is possible?
How can I handle that?
My Code here: https://codesandbox.io/s/3xv8xnx3z5
only you should convert Header component like following:
class Header extends Component {
state = {
focus: false
};
handleInputFocus = () => {
this.setState({ focus: true });
};
handleInputBlur = () => {
this.setState({ focus: false });
};
render() {
return (
<header className="ss_header">
<SearchBar
onFocus={this.handleInputFocus}
onBlur={this.handleInputBlur}
/>
{this.state.focus ? <ResultSearch /> : null}
</header>
);
}
}
and also in SearchBar component add following attributes to your input:
onFocus={this.props.onFocus}
onBlur={this.props.onBlur}
also, you should remove your CSS about result box.
And, you can see the updated code on the following sandbox:
https://codesandbox.io/s/mmj46xkpo9
Still not sure what you're trying to achieve.
This is the way you can handle visibility of result of the search. Let me know if this isn't what you're looking for.
https://codesandbox.io/s/7jvz31xr66

Another case of React CSS Transitions not applying classes

I am trying to get my React CSS Transition classes applied to my DOM elements. I have done all of the following:
Referenced this question, to check correct use case and this other question making sure I am using a key attribute even when rendering one child.
If I am understanding correctly the library has migrated and the way we import the library is a little different, but let's look at what I'm working with.
Relevant code:
import {CSSTransitionGroup} from "react-transition-group";
class NewTournament extends React.Component{
render(){
const style = {
active: { display: "flex", flex: 5 },
inactive: null
}
const dynamic = this.props.editTournament != null ? style.active : style.inactive
return(
<div className="left-column">
<div className="tournament-creator">
<div id="banner">
<h1>Build A Tournament Here</h1>
</div>
<form action="" className="tournamentBuilder">
<input type="text" placeholder="Tournament Name" ref="nameRef" onChange={() => this.recordName()}/>
<input type="number" defaultValue={prelims} ref="prelimRef" onChange={() => this.updatePrelims()} />
<input type="number" defaultValue={outRounds} ref="outRoundRef" onChange={() => this.updateOutround()}/>
<input type="text" placeholder="Notes" ref="notesRef" onChange={() => this.recordNote()}/>
</form>
<div id="submitButton" onClick={() => this.createTournament()}>
Create Tournament
</div>
</div>
<CSSTransitionGroup className="tournament-editor"
component="div"
transitionName="editBoxRail"
transitionEnterTimeout={10000}
transitionLeaveTimeout={10000}
style={dynamic}>
<TournamentEditor key="editor" />
</CSSTransitionGroup>
</div>
)
}
}
So you click a button in the UI and then the tournament editor component goes from display: none to display: flex. It is my understanding that this will trigger the classes to be applied and taken away, but they are never applied the only way I have been successful in doing so is adding the transitionAppear={true} attribute where they just sit there and never go away.
What am I not doing correctly? This has me stumped because I've successfully worked with the older library and I don't know why this is giving me so much trouble.

Categories

Resources