How to detect focus out on div - javascript

I am working on accessibility, so I am testing my app using TAB key. I would like to do something when following div element loses focus.
So in my imagination this onBlur function should only fire when I would click TAB key on button 2 and move to button 3. But this onBlur is call on every TAB click in inside this div. Why this is happening?
What should I do to fire function only when I will be outside of this div. So after click TAB key on button 2 and move to button 3, this function should be fired
export default function App() {
return (
<>
<div onBlur={() => console.log('Blur')} style={{ padding: '20px', border: '1px solid #000'}} tabIndex={0}>
<button>1</button>
<button>2</button>
</div>
<button>3</button>
</>
);
}

You can simply take advantage of the e.relatedTarget that is available in the onBlur callback to detect if:
The related target is the current target <div> itself, or
The related target is a descendant of the current target <div> by using the Node.contains method
If neither conditions are met, then you conditionally invoke the necessary logic:
<div
onBlur={(e) => {
if (
e.relatedTarget !== e.currentTarget &&
!e.currentTarget.contains(e.relatedTarget)
) {
console.log("Blur");
}
}}
tabIndex={0}
>
{/* Content here */}
</div>
I have made a proof-of-concept Codesandbox to demonstrate the code above, but I've swapped out the <button> with <input> just for a more visual test:

If you only want onBlur to fire when leaving button 2 you can just move the onBlur to button 2
return (
<>
<div style={{ padding: '20px', border: '1px solid #000' }} tabIndex={0}>
<button>1</button>
<button onBlur={() => console.log('Blur')}>2</button>
</div>
<button>3</button>
</>
);

Related

Bootstrap tooltip won't work after update/refresh the page

For some reason, my tooltip component is not working correctly. I assume it has something to do with the option attributes but not sure where I can fix it. I initialized the tooltip component by doing the following:
var options = {
animation: true,
container: "body",
placement: "bottom",
trigger: "hover focus",
};
const tooltipTriggerList = document.querySelectorAll(
'[data-bs-toggle="tooltip"]'
);
const tooltipList = [...tooltipTriggerList].map(
(tooltipTriggerEl) => new bootstrap.Tooltip(tooltipTriggerEl, options)
);
And here is the HTML section:
return (
<>
<div
className="card, StanderdizedBox rounded"
style={{ background: "white", margin: "10px" }}
>
<button
type="button"
className="btn btn-secondary"
data-bs-toggle="tooltip"
data-bs-custom-class="custom-tooltip"
data-bs-title="Search users and chats."
>
Search
</button>
</div>
</>
);
When I make some changes, for example, delete the "options" after "tooltipTriggerEl", the tooltip will work as long as I am not refreshing the web page.
Edit: Just found out my "options" attributes are not working as well.
Had a similar issue in SolidJS(similar to react).
The only solution I found is to bind a onMouseOver event and create a tooltip for every hover and calling show method on it.
<div class="col-3" onMouseOver={
(e) => {
$(e.target).tooltip({
html: true,
title: `Tooltip text`
});
$(e.target).tooltip('show');
}
}>
Some Text
</div>

How do I force label and dropdown to be on same line?

I want to force the dropdown and the label to be on the same line. How can I force this. Because for now I get the label : Taste above the dropdown.
export default function MenuItemDisplay() {
...
return (
<div>
...
<div className="TextData">
Taste : <CustomDropdown style={styles.select} options={TASTE} defaultValue={LIKELIHOOD.find((t) => t.label === item.taste)} />
</div>
...
</div >
);
}
CustomDropdown:
export default function CustomDropdown({ style, options, styleSelect, defaultValue, isMulti }) {
return <div style={style}>
<Select styles={styleSelect} options={options} defaultValue={defaultValue} isMulti={isMulti} />
</div>
}
Try this. or display:flex
.textData {
display:grid;
grid-template-columns:auto auto;
}
First thing that I would do is wrap your 'label' in paragraph tags, because from a semantics point of view text should not be wrapped solely in a div.
<div className="TextData">
<p>Taste :</p>
<CustomDropdown
style={styles.select}
options={TASTE}
defaultValue={LIKELIHOOD.find((t) => t.label === item.taste)}
/>
</div>
Secondly, in order to get everything on the same line, you can add 'display: flex' to the the TextData class. By default, content within a flexbox is on the same line.
If you then wish to center your content horizontally and vertically, you can add 'align-items: center' and 'justify-content: center' to the same div.

React scroll to ref with multiple scrollbars

I have a small problem that I can't figure out.
I have an element inside my page with a scrollbar. This means I got the main page scrollbar and a second scrollbar. I have a button inside that element that triggers a new div with some content inside of it. But that div is outside the view of the element so you need to scroll to see it. This is not really user friendly so I am trying to add a function that when you click on that button it scrolls to the new div.
Picture of element: https://imgur.com/8wIOTqo
button is the gold coloured one
The problem is that it is using the main page scrollbar and not the scrollbar of the element. Does anyone know how to fix this? Here is my code
// Function to open the element and scroll to the ref
function enableOtherAddressActive() {
secondDeliveryAddressRef.current.scrollIntoView();
setOtherAddress(true);
}
<div className="deliveryaddress__different">
{otherAddress ? (
<div className="deliveryaddress__different-btn btn btn--primary" onClick={disableOtherAddressActive}>Afwijkend bezorgadres verwijderen</div>
) : (
<div className="deliveryaddress__different-btn btn btn--primary" onClick={enableOtherAddressActive}>Afwijkend bezorgadres toevoegen</div>
)}
</div>
<div className="deliveryaddress__second" ref={secondDeliveryAddressRef}>
{otherAddress ? (
<div className="deliveryaddress__inner">
<h3 className="deliveryaddress__title">
Afwijkend bezorgadres toevoegen
</h3>
</div>
) : undefined}
</div>
</div>
One of the way to scroll to the element is assigning a id to the div and using scrollInto that
I have done in the codesandbox below refer it shows how to scroll into a particular element even if it is nested scrollbar
Code:
const handleScrollTo = () => {
setTimeout(() => {
document.getElementById(`element`) &&
document.getElementById(`element`).scrollIntoView({
behavior: "smooth",
block: "center"
});
}, 1000);
};

onMouseEnter doesn't work when mouse go fast through the element

I know that this question peoples asked many times but I've not found any answer which give me opportunity to solve this issue
<Zoom in timeout={500}>
<div
onMouseEnter={() => {
console.log('enter')
}}
onMouseLeave={this.handlePopoverClose}
className={classes.paperInside}>
{providers.map((entity, index) => {
return (<GameBox
key={index + 'box'}
element={entity}
isDivider={index === 3 && index !== 0}
/>)
})}
<Count
count={count}
to={`/games/${type}`}
sectionName={element.name}
/>
</div>
</Zoom>
Lets imagine that I have some div element , when I try go with my mouse through this element fast it doesn't work . I know that if you not enter element onMouseLeave will not work. But I really need that onMouseLeave triggers each time when i enter end then leave it . Pls if my question isn't clear enough let me know
Your scenario works for me as expected. I don't know what problem you are really facing.
You can have a look at my example
<!doctype html>
<html>
<head><title>onmouse event demo</title>
</head>
<body>
<h3>onmouse event demo</h3>
<p>Fires when the mouse pointer enters and leave the element.</p>
<div id="mouse_event" style="width:300px;height:100px;border:1px solid;" onMouseEnter="javascript:document.getElementById('mouse_event').innerHTML = 'enter event has been triggered' " onMouseLeave="javascript:document.getElementById('mouse_event').innerHTML = 'leave event has been triggered' ">Demo text</div>
</body>
</html>
working demo

How to get as e.target the exact element at which onClick is specified?

I have a React Component and give it onClick event handler:
function Item(props) {
return <li onClick={props.onClick}>{props.children}</li>
}
Then I use the Component like this:
<Item onClick={ function(e) {console.log(e.target)} }>
<span>This element is returned as e.target if clicked on it!</span>
</Item>
When I click on the text, the span element is logged as target and when it is clicked outside given span, li element is logged as target.
The problem is:
If there is a lot of child elements inside li element, and id or name are have to be gotten, it becomes a "hacky" task...
The question is:
Is it possible to get inside a handler function as e.target the exact element at which onClick is specified (not it's children; in this case li)?
PS. No jQuery for solution if possible.
event.target will always give you the element, which dispatched the event. In order to get the element who's listener is currently processed, you have to use event.currentTarget.
This should help: https://developer.mozilla.org/en-US/docs/Web/API/Event/Comparison_of_Event_Targets
Here is a simple example to illustrated your issue:
const Inner = () => <div className="inner">Inner</div>
const Outer = () => {
const clickHandler = e => {
console.log('target:', e.target.getAttribute('class'));
console.log('currentTarget:', e.currentTarget.getAttribute('class'));
};
return (<div className="outer" onClick={clickHandler}><Inner /></div>);
};
ReactDOM.render(<Outer/>, document.getElementById('app'));
.outer {
background: rosybrown;
padding: 40px;
}
.inner {
background: cornsilk;
padding: 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
Yes
const { render } = ReactDOM;
function Item(props) {
return <li onClick={props.onClick}
{props.children}
</li>
}
render(
<Item onClick = {
function(e) {
console.log(e.currentTarget)
}
}>
<span> This element is returned as e.target if clicked on it! </span>
</Item>,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

Categories