I was Wondering how to give style to two tags in react without using the className(as not using className is the main challenge).
Menu Here
Click Me
So for the "curry dish," it should only underline when hovering.
And for the click me it should be underlined first and disappear while hovering on it.
I got both underlines removed using the code below. But still can't figure out how to apply separate styling please help.
a: hover {
text-decoration: underline;
}
**Tags in react without using the className:**
<span style={{color: "red",cursor: "pointer",
text-decoration: underline !important }}>
Menu Here
</span>
If you're not using CSS you can do this with a simple stateful react component.
const UnderlineHover = ({children, ...rest}) => {
const [isHover, setIsHover] = useState(false);
const style = isHover ? {textDecoration: "underline"} : {};
return <a onMouseEnter={() => setIsHover(true)}
onMouseLeave={() => setIsHover(false)}
style={...style}
{...rest}
>{children}</a>;
};
you can try with state and style like=>
const [hover,setHover] = useState("")
const handleMouseEnter =()=>{
setHover(true)
}
const handleMouseExit =()=>{
setHover(false)
}
const linkStyle = {
text-decoration: hover? underline:none;
}
return(
<a href="" style={linkStyle} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseExit}>Menu Here</a>
<a href="" style={linkStyle} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseExit}>Click Me </a>
)
Hope this will help to solve out your problem. If you still facing issue just lemme know, i will help you more.
Thanks
Related
I have a multi page form that renders a list of buttons for each possible answer.
I am currently using getElementByID to change the button style when a button is clicked. I think this is not considered good practice in react.
can I use the useRef hook to target the DOM element and change its style instead of using getElementByID if the buttons are dynamically displayed with map?
{answers.map((answer, count = 0) => {
return (
<Button
key={count}
id=`button${count}`
onClick={(e) => {
document.getElementById(`${e.currentTarget.id}`).style.color = "white";
}}
>
<ButtonTitle>{answer.name}</ButtonTitle>
</Button>
);
})}
(animations on safari are breaking the active style, so I can't use the active pseudo element)
You can do this by adding a new state and toggle active class by that state.
Code something like this.
const [activeindex, setActiveIndex] = useState("");
return(
<>
{answers.map((answer, count = 0) => {
return (
<Button
key={count}
className={count==activeindex?"acvie":""}
onClick={(e) => {
setActiveIndex(count)
}}
>
<ButtonTitle>{answer.name}</ButtonTitle>
</Button>
);
})}
}
</>
And use .active class in css file.
In the image as you can see, I have a Foo page, where I have 10 Accordions, In one of the Accordions there is a Form component, When I submit the Form it calls a remote API and returns some JSON data, I convert it to a Table of content and want to show it under the Form.
The problem is I can show the Table after toggling the Accordion again after the submit button clicked, as I have set the maxheight in the onClick.
const [activeState, setActiveState] = useState("");
const [activeHeight, setActiveHeight] = useState("0px");
const toogleActive = () => {
setActiveState(activeState === "" ? "active" : "");
setActiveHeight(activeState === "active" ? "0px" :`${contentRef.current.scrollHeight}px`)
}
return (
<div className={styles.accordion_section}>
<button className={styles.accordion} onClick={toogleActive}>
<p className={styles.accordion_title}>{title}</p>
</button>
<div ref={contentRef}
style={{ maxHeight: `${activeHeight}` }}
className={styles.accordion_content}>
<div>
{content}
</div>
</div>
</div>
)
I have used context also to share the useState hook between Accordion and Form components to update the height.
<UpdateHeightContext.Provider value={{updateHeight, setUpdateHeight}}>
<Accordion title="Find your Data" content={< FormWithTwoInput firstLabel="FirstName" secondLabel="LastName" buttonColor="blue" buttonText="Check Deatils"/>} />
</UpdateHeightContext.Provider>
Is there any way to update the Accordions height dynamically when I receive the response from the API? Other than toggling it again. A similar question was asked here React accordion, set dynamic height when DOM's children change unfortunately no one replied.
Even though the working around what I have found is not a robust one, but it is working completely fine for me. If someone stumbles upon this same issue might find this useful.
import React, { useState, useRef } from 'react'
const Accordion = ({ title, content }) => {
const [activeState, setActiveState] = useState("");
const [activeHeight, setActiveHeight] = useState("0px");
const contentRef = useRef("form")
const toogleActive = () => {
setActiveState(activeState === "" ? "active" : "");
setActiveHeight(activeState === "active" ? "0px" :`${contentRef.current.scrollHeight + 100}px`)
}
return (
<div className={styles.accordion_section}>
<button className={styles.accordion} onClick={toogleActive}>
<p className={styles.accordion_title}>{title}</p>
</button>
<div ref={contentRef}
style={{ maxHeight: `${activeHeight}` }}
className={styles.accordion_content}>
<div>
{content}
</div>
</div>
</div>
)
}
Accordion.propTypes = {
title: PropTypes.string,
content: PropTypes.object,
}
export default Accordion
I have hardcoded some extra space so that while the dynamic response is accepted the Table content is shown. In the CSS module file, I have kept the overflow as auto, earlier it was hidden.
.accordion_content {
background-color: white;
overflow: auto;
max-height: max-content;
}
As a result, the Table is appearing dynamically and the user can scroll inside the Accordion if my Table needs larger space.
I'm new to React, Nodejs and JavaScript so bear with me.
I'm doing some practice with onClick events to change text by clicking some buttons, I have an input type="checkbox" to make the text bold when checked and vise versa, 2 buttons to increase and decrease the text size by 1+ or 1- and a span that shows the current text size (16 is my default), and finally a span with the id="textSpan" that have the text meant to be modified. I also want this buttons, the checkbox and the span with the id="fontSizeSpan" that shows the current font size to be hidden by default and when you click the text it appears on its left.
This is the code so far:
class FontChooser extends React.Component {
constructor(props) {
super(props);
this.state = {hidden: true};
this.checkInput = React.createRef();
this.hide = React.createRef();
}
toggle(){
this.setState({hidden: !this.state.hidden});
this.hide.current
}
makeBold(){
this.setState({bold: !this.state.bold});
this.checkInput.current
}
changeSize(){
this.setState({size: !this.props.size})
for(var i = this.props.size; i <= this.props.max; i++);
}
render() {
return(
<div>
<input type="checkbox" id="boldCheckbox" ref={this.hide} hidden={false} onClick={this.makeBold.bind(this)}/>
<button id="decreaseButton" ref={this.hide} hidden={false}>-</button>
<span id="fontSizeSpan" ref={this.hide} hidden={false}>{this.props.size}</span>
<button id="increaseButton" ref={this.hide} hidden={false} onClick={this.changeSize.bind(this)}>+</button>
<span id="textSpan" ref={this.checkInput} onClick={this.toggle.bind(this)}>{this.props.text}</span>
</div>
);
}
right now their hidden attribute is false so I can see them.Here's the html which is not much:
<div id='container'></div>
<script type="text/jsx">
ReactDOM.render(
<div>
<FontChooser min='4' max='40' size='16' text='You can change me!' bold='false'/>
</div>,
document.getElementById('container'))
;
</script>
So far all I have managed is for the browser console(I'm using Firefox react component addon) to confirm there is a functioning event that doesn't really work, as in when I click the text, the buttons or the input checkbox the props does change to false or true every click but that's about it.
I appreciate it if someone could guide me through this.
NOTE:
just in case nothing is imported, also I setup a local server with Nodejs
Here is an Example of what you want: https://codesandbox.io/s/mystifying-cookies-v7w3l?file=/src/App.js
Basically, I have 4 variables: text, fontWeight, fontSize and showTools.
Each button has its own task and also you can select if show or not.
In React you don't have to care about ids like in older frameworks. You can generate the elements just in the place where you are with the information which you need. So, basically, we have the 4 variables and use them wisely where we want (as styles props, as text and even as a conditional to show components). It's the magic of React and JSX.
In the code I've use hooks, part of the latest definition of React. For that my Components is functional and not a Class. it makes it easier and faster for examples and prototyping.
The tools are show by default just to let you play with it
import React from "react";
import "./styles.css";
export default function App() {
const [text, setText] = React.useState("");
const [boldFont, setBoldFont] = React.useState(false);
const [fontSize, setFontSize] = React.useState(14);
const [showTools, setShowTools] = React.useState(true);
return (
<div className="App">
<div
style={{
fontWeight: boldFont ? "bold" : "normal",
fontSize: `${fontSize}px`
}}
>
<span onClick={() => setShowTools(!showTools)}>
{text || "Text Example"}
</span>
</div>
{showTools && (
<div>
<button onClick={() => setBoldFont(!boldFont)}>Bold</button> |
<button onClick={() => setFontSize(fontSize + 1)}>A+</button>
<button onClick={() => setFontSize(fontSize - 1)}>a-</button>
<input
type="text"
value={text}
onChange={event => {
setText(event.target.value);
}}
/>
</div>
)}
</div>
);
}
I have a react component like this -
const MyComponent = () => (
<ContainerSection>
<DeleteButtonContainer>
<Button
theme="plain"
autoWidth
onClick={() => {
onDeleteClick();
}}
>
Delete
</Button>
</DeleteButtonContainer>
</ContainerSection>
);
I want to show the DeleteButtonContainer only when the user hovers over ContainerSection. Both of them are styled-components. I couldn't find any way to do it using just css (using hover state of parent inside child), so I used something like this using state -
const MyComponent = ()=>{
const [isHoveredState, setHoveredState] = useState<boolean>(false);
return (<ContainerSection onMouseEnter={() => setHoveredState(true)} onMouseLeave={() => setHoveredState(false)}>
<DeleteButtonContainer style={{ display: isHoveredState ? 'block' : 'none' }}>
<Button
theme="plain"
autoWidth
disabled={!isHoveredState}
onClick={() => {
onDeleteClick();
}}
>
Delete
</Button>
</DeleteButtonContainer>
</ContainerSection>)
};
Now I want to always show DeleteButtonContainer when it's on mobile device since it doesn't have hover. I know I can always right more JS to achieve this, but I want to do it using CSS and if possible I want to remove state completely.
So is there a way to achieve this using just styled component and not writing custom JS?
You can reference one component in another, and use media queries to enable the rule for non mobile resolutions.
Hover the the golden bar to see the button, and shrink the width to disable the hover rule.
const DeleteButtonContainer = styled.div``;
const ContainerSection = styled.div`
height: 2em;
background: gold;
#media (min-width: 640px) { // when resolution is above 640px
&:not(:hover) ${DeleteButtonContainer} { // if DeleteButtonContainer is not under an hovered ContainerSection
display: none;
}
}
`;
const Button = styled.button``;
const MyComponent = () => (
<ContainerSection>
<DeleteButtonContainer>
<Button>
Delete
</Button>
</DeleteButtonContainer>
</ContainerSection>
);
ReactDOM.render(
<MyComponent />,
root
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/styled-components/4.4.0/styled-components.js"></script>
<div id="root"></div>
I am trying to implement a breadcrumb layout in my react project. I am not using router4 to render the URL.
At the moment the breadcrumbs appear like this.
Home
|Test Update
|Testssss
|Test11111
And i would like to have them all on one line.
home|Test Update|Testssss|Test11111
This is my code.
renderBreadCrumbs=(classes)=>{
const {folderPathNames } = this.state;
let items =[]
if(!!folderPathNames){
items = folderPathNames.map((folder,index)=>{
return <div key={index}>
<a className={classes.rowalign}
onClick={this.handleFolderDestination}
data-folder={folder.id}>|{folder.name}
</a>
</div>
})
return items
}
}
I tried to make all the components go to the same line by using the display-inline but it did not work.
styles:
rowalign:{
display: 'inline-block'
}
I also tried doing inline styling:
const divStyle = {
display: 'inline-block'
};
and put that into my code on this line
<a style={divStyle}
onClick={this.handleFolderDestination}
data-folder={folder.id}>
{folder.name}
</a>
when i inspect the element in chrome i get
<a data-folder="206" style="display: inline-block;">|Testssss</a>
Can anyone tell me how to make the foldernames appear on the same line?
You should use style props to apply inline styles, not className as per your code. Note div should be outside of all a as a container of them.
Write your code as:
renderBreadCrumbs=(classes)=>{
const {folderPathNames } = this.state;
let items =[]
if(!!folderPathNames){
items = folderPathNames.map((folder,index)=>{
return (
<a style={divStyle}
key={index}
onClick={this.handleFolderDestination}
data-folder={folder.id}>|{folder.name}
</a>
)
})
return <div>{items}</div>
}
}