My project has a reusable tooltip component that utilizes reactstrap tooltip to show the tooltip. The usage is shown below
import { UncontrolledTooltip } from 'reactstrap';
const Tooltip = ({
target,
title,
trigger,
position,
delay,
size,
boundariesElement,
}) => {
return (
<div className={TooltipStyles.tooltip}>
{title.length && target && (
<UncontrolledTooltip
cssModule={TooltipStyles}
placement={position}
target={target}
trigger={trigger}
delay={delay}
defaultOpen={false}
popperClassName={TooltipStyles.tooltipFade}
innerClassName={classNames({
[TooltipStyles.textSizeSmall]: size === 'small',
[TooltipStyles.textSizeDefault]: size === 'default',
[TooltipStyles.textSizeLarge]: size === 'large',
})}
boundariesElement={boundariesElement}
>
{title}
</UncontrolledTooltip>
)}
</div>
);
};
I want to create a multi-line tooltip to show a list of items. Basically, I want the title prop to render a multi-line string. Can someone please guide me on how to do this?
I tried sending HTML in the title prop but it doesn't work.
Send title as html, add <br /> tags.
Below code show tooltip in 2 lines
<p>Somewhere in here is a <span style={{textDecoration: 'underline', color:'blue'}} href='#' id='UncontrolledTooltipExample'>tooltip</span>.</p>
<UncontrolledTooltip placement='right' target='UncontrolledTooltipExample'>
Hello <br />world!
</UncontrolledTooltip>
</div>
I tried sending HTML in the title prop but it doesn't work. :(
You need to send it as JSX not as html string
title='Hello<br />World' will not work
title={<>Hello<br />World</>} should work
Use below code in your example and see it working
import React from 'react';
import Tooltip from '#bit/reactstrap.reactstrap.tooltip';
class Example extends React.Component {
constructor(props) {
super(props);
this.toggle = this.toggle.bind(this);
this.state = {
tooltipOpen: false
};
}
toggle() {
this.setState({
tooltipOpen: !this.state.tooltipOpen
});
}
render() {
return (
<div>
<link
rel='stylesheet'
href='https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css'
/>
<p>Somewhere in here is a <span style={{textDecoration: 'underline', color:'blue'}} href='#' id='TooltipExample'>tooltip</span>.</p>
<Tooltip placement='right' isOpen={this.state.tooltipOpen} target='TooltipExample' toggle={this.toggle}>
{this.props.title}
</Tooltip>
</div>
);
}
}
export default <Example title={<>Line one<br />Line 2<br />Line3</>} />
Related
thank you for reading this. I am attempting to learn React by making a dummy website, however I've run into a roadblock.
I want the "display-page" div to only show the Send element initially (which is easy) but when someone clicks one of the 4 options from the content_bar div I want remove the current element and only show the newly clicked element (in this case it is 'Transactions')
I've read about useState and routing but I'm not sure how to implement
Thanks! Please let me know if I didnt give enough details
import React, { Component } from 'react';
import './Data.css';
import Transactions from './Transactions';
import Send from './Send';
class Data extends Component {
constructor(props) {
super(props);
this.state = {
content: <Send />
}
}
transactionpage = () => {
this.setState({content: <Transactions/>});
}
render() {
return(
<div className="content">
<div className="content_bar">
<h5>Send</h5>
<h5 onClick={this.transactionpage}>Transactions</h5>
<h5>Friends</h5>
<h5>Professional</h5>
</div>
<div className="display-page">
{this.state.content}
</div>
</div>
);
}
}
export default Data;
Looking at You can't press an <h5> tag and React code without state feels strange.
You need to learn more to achieve your goal, these are the topics:
JSX expresssion
Conditional rendering
State management
Let me show you my solution, it is one of many ways.
class Data extends Component {
constructor(props) {
super(props);
this.state = {
toDisplay: ''
};
this.changeToDisplay = this.changeToDisplay.bind(this);
}
changeToDisplay(e) {
this.setState({ toDisplay: e.target.textContent.toString() });
}
render() {
return (
<div className="content">
<div className="content_bar">
<button onClick={e => changeToDisplay(e)}>Send</button> <br />
<button onClick={e => changeToDisplay(e)}>Transactions</button> <br />
<button>Friends</button> <br />
<button>Professional</button> <br />
</div>
<div className="display-page">
{this.state.toDisplay === 'Send' ? <Send /> : null}
{this.state.toDisplay === 'Transactions' ? <Transactions /> : null}
</div>
</div>
);
}
}
I'm trying to get the Menu (from #szhsin/react-menu module) element buttons to show up to the right of the previous generated item, however I'm a bit lost as to how to get it to do so. Everything results in the element showing below previous.
import React from 'react';
import {
Menu,
MenuItem,
MenuButton,
SubMenu
} from '#szhsin/react-menu';
import '#szhsin/react-menu/dist/index.css'
class TopMenuDropdown extends React.Component {
constructor(props) {
super(props);
}
render () {
return (
<div>
{this.props.TMPMenuTestCategory.map (({name,items},i) =>
{
return <Menu
align={'end'}
key={i}
menuButton={<MenuButton>{name}</MenuButton>}
reposition={'initial'}
>
{items.map((item,j) =>
{
console.log(item,j);
return <MenuItem key={j}>{item}</MenuItem>
}
)}
</Menu>
} )}
</div>
)
}
}
I was looking through the documentation on https://szhsin.github.io/react-menu/docs , however, me trying the following has had no effect:
Assigning the display:'inline' or 'flex' the <Menu> or to a <div><Menu> as I attempted to give each menu it's own div when generated.
Wrapping each generated menu in a <span>
Fiddling with the Menu item's props like 'align' , 'position' , and 'reposition' (though I'm guessing Reposition needs an additional RepositionFlag to work if I understand it correctly)
Here's the snippet of index.JS it is part of
const basicMenuArray = [
{ name: 'ProTIS', items: [ 'Login', 'Exit' ] },
{ name: 'Project', items: [ 'Open', 'Info' ] },
]
class App extends React.Component {
state={
language:'sq'
}
render () {
return (
<div >
<div style={{display:'flex', width:'75%', float:'left' }}>
<span> Temp Text </span>
</div>
<div style={{display:'flex', width:'25%'}}>
<span style={{marginLeft:'auto'}}>
<DataComboBox
dropdownOptions={languages}
value={this.state.language}
valueField='language_code'
textField='language_full_name'
onChange={(value) => alert(JSON.stringify(value))}
/>
</span>
</div>
<div>
<TopMenuDropdown TMPMenuTestCategory={basicMenuArray} />
</div>
</div>
);
}
}
So I ended up realizing something this morning, as I'm learning ReactJS still, and my brain did not process the things properly.
I changed the initial
<div>
to
<div style={{display:'flex'}}>
and added a style={{display:'flex', float:'left'}} to the <Menu> which generates the button.
the final code snippet looks like this for anyone still learning like I am :)
return (
<div style={{display:'flex'}}>
{this.props.TMPMenuTestCategory.map (({name,items},i) =>
{
return <Menu
style={{display:'flex', float:'left'}}
key={i}
menuButton={<MenuButton>{name}</MenuButton>}
>
{items.map((item,j) =>
{
console.log(item,j);
return <MenuItem key={j}>{item}</MenuItem>
}
)}
</Menu>
} )}
</div>
)
I have an example of a toggle that hide/display content.
I used https://www.npmjs.com/package/react-animated-css and it worked perfectly when displaying the content, meaning that after showing the content the animation is playing.
Now that I press the toggle button, the content instantly vanishes without animation.
I checked in the console and the class for the animationOut is working, but it seems that the content closes before the animation have the time to play, so it's hidden.
How to fix this issue ?
The working code : https://stackblitz.com/edit/react-sorgz5?file=src/App.js
import React, { Component } from "react";
import ContentComponent from "./content.js";
import { Animated } from "react-animated-css";
export default class toggleComponent extends React.Component {
constructor() {
super();
this.state = {
isShowBody: false
};
}
handleClick = event => {
this.setState({ isShowBody: !this.state.isShowBody });
};
checkbox = () => {
return (
<div>
<span className="switch switch-sm">
<label>
<input
type="checkbox"
name="select"
onClick={this.handleClick.bind(this)}
/>
<span />
</label>
</span>
</div>
);
};
render() {
return (
<div>
{this.checkbox()}
<Animated
animationIn="bounceInLeft"
animationOut="fadeOut"
isVisible={this.state.isShowBody}
>
<div>{this.state.isShowBody && <ContentComponent />}</div>
</Animated>
</div>
);
}
}
Solved. I needed to remove this.state.isShowBody in <div>so the condition of the visibility is controller by isVisible.
<Animated
animationIn="bounceInLeft"
animationOut="fadeOut"
isVisible={this.state.isShowBody}
>
<div>{<ContentComponent />}</div>
</Animated>
I have this component form react-tooltip where I pass some props and it creates the tooltip. I want the place of the tooltip to be "top" on default, but when I pass the props to be in a different place, to change it.
class Tooltip extends PureComponent {
render() {
const { text, element, type, place, className } = this.props;
return (
<div data-tip={text} className="m0 p0">
{element}
<ReactTooltip
type={type}
place={place}
effect="solid"
className={className}
html
/>
</div>
);
}
}
Tooltip.defaultProps = {
type: 'info',
place: 'top',
className: 'tooltip-top',
};
Tooltip.propTypes = {
text: PropTypes.string.isRequired,
element: PropTypes.element.isRequired,
type: PropTypes.string,
place: PropTypes.sring,
className: PropTypes.sring,
};
export default Tooltip;
Then I have this other component where I pass some props to the Tooltip component and I just want this only component to be placed on the bottom.
<Tooltip
type="warning"
place="bottom"
className="tooltip-bottom"
text={
'Ingrese los datos de la información financiera histórica de su compañía en la plantilla'
}
element={
<div className={`center mt3 ${styles.optionButton}`}>
<NavLink
className="btn btn-primary"
to={`${path}/manual-upload`}
>Continuar</NavLink>
</div>
}
/>
The problem is that is rendering in the bottom but also on the top. How can I make this to only appear on the bottom (in this component and the rest of the tooltips on the top). Thanks ;)
If you use <ReactTooltip /> inside a loop then you will have to set a data-for and id for each one.
const Tooltip = ({ children, data }) => {
const [randomID, setRandomID] = useState(String(Math.random()))
return (
<>
<div data-tip={data} data-for={randomID}>{children}</div>
<ReactTooltip id={randomID} effect='solid' />
</>
)
}
export default Tooltip
I ran into this issue today as well, I was able to get it resolved, this might not be relevant to you anymore, but for people looking:
I had this issue with data-for and id as well, the solution for me
was to set a more unique identifier/a combination of a word and a
variable that I was getting from the parent component (i.e.
id=`tooltip-${parent.id}`).
Heres the same
issue.
I have an accordion in React formed of a row component which is looped inside a body parent component. In the row I'm toggling the state showDetails to show/hide the details for each row, effectively opening the accordion item. But, since the state is for each row, how do I close one accordion item when I open another one?
Body:
export default class Body extends React.Component {
render() {
const {modelProps, showInfo, linkedRow} = this.props;
return (
<div className="c-table__body">
{this.props.model.map(
(subModel, i) =>
linkedRow ?
<LinkedRow
key={`${i}`}
model={subModel}
modelProps={modelProps}
/>
:
<Row
key={`${i}_${subModel.username}`}
model={subModel}
modelProps={modelProps}
showInfo={showInfo}
handleStatusChanged={this.props.handleStatusChanged}
/>
)}
</div>
);
}
}
Row:
class Row extends React.Component {
constructor(props) {
super(props);
this.state = {
userId: '',
showDetails: false,
showModal: false,
status: '',
value: '',
showInfo: false
};
render() {
const { model, modelProps, showInfo } = this.props;
return (
<div className="c-table__row">
<div className="c-table__row-wrapper">
{modelProps.map((p, i) => (
<div className={`c-table__item ${this.isStatusCell(model[p]) ? model[p] : p}`} key={i}>{this.isStatusCell(model[p]) ? this.toTitleCase(model[p]) : model[p]}</div>
))}
{showInfo ? (
<div className="c-table__item c-table__item-sm">
<a
name="view-user"
onClick={this.showDetailsPanel}
className={this.state.showDetails ? 'info showing' : 'info'}
>
<Icon yicon="Expand_Cross_30_by_30" />
</a>
</div>
) : (
''
)}
</div>
{this.state.showDetails ? (<ConnectedDetails user={model} statusToggle={this.handleStatusChange}/>) : null}
</div>
);
}
}
export default Row;
Not really sure how to approach this, maybe something in the body that check is there's any row open according to the showDetails state in the rows?
Thanks in advance
The approach is to lift the state of which <Row /> is open to the <Body /> component.
Also the method that switch between opened <Row /> is on the <Body /> component.
toggleOpen = (idx) => {
this.setState({ openRowIndex: idx });
}
then when you rendered your <Row />s you can pass a prop isOpen:
<Row
key={`${i}_${subModel.username}`}
model={subModel}
modelProps={modelProps}
showInfo={showInfo}
handleStatusChanged={this.props.handleStatusChanged}
isOpen={this.state.openRowIndex === i}
onToggle={_ => this.toggleOpen(i)}
/>