Reputation: 25830
I've been trying to find code to simulate mouseover
in Chrome but even though the "mouseover" listener gets fired, the CSS "hover" declaration is never set!
I tried also doing:
//Called within mouseover listener
theElement.classList.add("hover");
But nothing seems to change the element to what is declared in its hover
declaration.
Is this possible?
Upvotes: 124
Views: 160034
Reputation: 1535
You can simulate the mouseover event like this:
const element = document.getElementById('name');
element.addEventListener('mouseover', function() {
console.log('Event triggered');
});
function doTheThing() {
var event = new MouseEvent('mouseover', {
'view': window,
'bubbles': true,
'cancelable': true
});
element.dispatchEvent(event);
}
#name:hover {
background-color: blue;
}
<div id="name">My Name</div>
<button type="button" onclick="doTheThing()">Click me</button>
Upvotes: 93
Reputation: 101
I would like to mention a different approach to this question using css only but I am assuming here that :hover
will be triggered in circumstance of a change in one of the parent tags as follows:
function btn_activated(){
const button = document.querySelector('button.btn');
if(button.classList.contains('active')){
button.classList.remove('active');
}else{
button.classList.add('active');
}
}
.btn{
width: 100px;
height: 30px;
}
.btn:hover > span.visually-hidden,
.active> span.visually-hidden{
display: inline;
}
.visually-hidden{
display: none;
}
<button class="btn" onClick="btn_activated()">
<span class="visually-hidden">
hovered
</span>
</button>
It is possible to apply this concept to any nested tags but one of the parent tags should have its classList changed at least.
Upvotes: 0
Reputation: 15356
What I usually do in this case is adding a class using javascript.. and attaching the same CSS
as the :hover
to this class
Try using
theElement.addEventListener('onmouseover',
function(){ theElement.className += ' hovered' });
Or for older browsers:
theElement.onmouseover = function(){theElement.className += ' hovered'};
you will of course have to use onmouseout
to remove the "hovered" class when you leave the element...
Upvotes: 7
Reputation: 595
I stumbled upon this question while trying to write automated tests, to verify, that a certain set of elements on a given page all receive have the some set of css properties set by the css for on hover events.
While the above answer perfectly explains, why it is not possible to simply trigger the hover event by JS and then probe some css value of interest, it does answer the initial question "How do I simulate a mouseover in pure JavaScript that activates the CSS “:hover”?" only partly.
This is not a performant solution. We use it only for automated testing, where performance is not a concern.
simulateCssEvent = function(type){
var id = 'simulatedStyle';
var generateEvent = function(selector){
var style = "";
for (var i in document.styleSheets) {
var rules = document.styleSheets[i].cssRules;
for (var r in rules) {
if(rules[r].cssText && rules[r].selectorText){
if(rules[r].selectorText.indexOf(selector) > -1){
var regex = new RegExp(selector,"g")
var text = rules[r].cssText.replace(regex,"");
style += text+"\n";
}
}
}
}
$("head").append("<style id="+id+">"+style+"</style>");
};
var stopEvent = function(){
$("#"+id).remove();
};
switch(type) {
case "hover":
return generateEvent(":hover");
case "stop":
return stopEvent();
}
}
generateEvent reads all css files, , replaces :hover with an empty string and applies it. This has the effect, that all :hover styles are applied. Now one can probe for a howered style and set back to initial state by stopping the Simulation.
Why do we apply the hover effect for the whole document and not just for the element of interest by getting the from the sheets and then perform a element.css(...)?
Done as that, the style would be applied inline, this would override other styles, which might not be overriden by the original css hover-style.
How would I now simulate the hover for a single element?
This is not performant, so better don't. If you must, you could check with the element.is(selectorOfInterest) if the style applies for your element and only use those styles.
In Jasmine you can e.g. now perform:
describe("Simulate CSS Event", function() {
it("Simulate Link Hover", function () {
expect($("a").css("text-decoration")).toBe("none");
simulateCssEvent('hover');
expect($("a").css("text-decoration")).toBe("underline");
simulateCssEvent('stop');
expect($("a").css("text-decoration")).toBe("none");
});
});
Upvotes: 21
Reputation: 85
I'm assuming you want to inspect the CSS after dom manipulation, but as soon as you move your mouse back to the devtools, the event isn't active on that html element anymore. You probably would like to have something like the :hover option in devtools for your javascript events. That doesn't exist, but you can simulate it.
Since javascript is disabled, it doesn't get the chance to modify the element(s) back again. You can go to the devtools and inspect the css and html as if you were hovering, clicking or doing something else with it. After you're done, go to the command panel again and select 'enable javascript'.
Upvotes: 4
Reputation: 28687
You can use pseudo:styler, a library which can apply CSS pseudo-classes to elements.
(async () => {
let styler = new PseudoStyler();
await styler.loadDocumentStyles();
document.getElementById('button').addEventListener('click', () => {
const element = document.getElementById('test')
styler.toggleStyle(element, ':hover');
})
})();
Disclaimer: I am a coauthor of this library. We designed it to additionally support cross-origin stylesheets, specifically for use in Chrome extensions where you likely lack control over the CSS rules of the page.
Upvotes: 8
Reputation: 276306
You can't. It's not a trusted event.
Events that are generated by the user agent, either as a result of user interaction, or as a direct result of changes to the DOM, are trusted by the user agent with privileges that are not afforded to events generated by script through the DocumentEvent.createEvent("Event") method, modified using the Event.initEvent() method, or dispatched via the EventTarget.dispatchEvent() method. The isTrusted attribute of trusted events has a value of true, while untrusted events have a isTrusted attribute value of false.
Most untrusted events should not trigger default actions, with the exception of click or DOMActivate events.
You have to add a class and add/remove that on the mouseover/mouseout events manually.
Upvotes: 141