FocusOut/Blur when leaving div with elements - javascript

There is a fixed div with some links that are shown when user clicks a button.
For accessibility purposes, I want to close this div when it loses keyboard focus, but I can`t find the correct DOM event to handle.
I've tried blur and focusout events but they are also triggered even when children elements still has focus.
Example:
function openMenu() {
var menu = document.getElementById("menu");
menu.setAttribute("open", "");
menu.addEventListener("focusout", handleMenuFocusOut);
menu.focus();
}
function closeMenu() {
var menu = document.getElementById("menu");
menu.removeAttribute("open");
}
function handleMenuFocusOut() {
console.log("Event triggered!");
menu.removeEventListener("focusout", handleMenuFocusOut);
closeMenu();
}
#menu {
display: none;
position: fixed;
top: 50px;
padding: 20px;
background-color: gray;
}
#menu[open] {
display: block;
}
#menu:focus, a:focus {
background-color: cyan;
}
<div>
<button onclick="openMenu()">Click Me</button>
<div id="menu" tabindex="0">
<ul>
<li>Link 1</li>
<li>Link 2</li>
<li>Link 3</li>
</ul>
</div>
<input type="text"/>
</div>
To reproduce the case, click the button and press tab to navigate between links.
The expected behavior is to close div only when focusing outside elements, like the textbox.

Ok, I've completely changed this answer.
You can do this using pure CSS using focus-within and ~ (which is used to show the menu when the open-button is focused.
Take a look at this snippet which uses no JS:
#menu {
display: block;
position: fixed;
top: 50px;
padding: 20px;
background-color: cyan;
opacity: 0;
pointer-events: none;
}
*:focus { outline: 3px solid #ff0; }
#menu:focus-within, #open-btn:focus ~ #menu {opacity: 1; pointer-events: all;}
<div>
<button id="open-btn">Click Me</button>
<div id="menu" tabindex="0">
<ul>
<li>Link 1</li>
<li>Link 2</li>
<li>Link 3</li>
</ul>
</div>
<input type="text" />
</div>

Related

Read More Function for unordered list using jQuery with Paragraph

I'm a beginner, and trying to understand everything. I tried using <p> and it works smoothly but when I insert a text like a ul and li it wont show up
I also tried using a div but only the <a> part is working not the ul and li. I hope someone can help me.
$(document).ready(function() {
$(".more-less").click(function() {
$(this).parent().prev('ul.more').toggleClass("main");
if ($(this).parent().prev('ul.more').hasClass('main')) {
$(this).text('Read Less');
} else {
$(this).text('Read More');
}
});
});
.more {
text-align: left !important;
display: none;
}
.more-less {
/* position: absolute; */
/* right: -30px; */
/* top: -34px; */
color: #e43330 !important;
text-align: center;
float: left;
width: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<p style="text-align: left;">First paragraph then cuts...
<p class="more">Second paragraph.</p>
<p><strong>Header key roles</strong></p>
<ul class="more">
<li>trait 1</li>
<li>trait 2</li>
<li>trait 3</li>
<li>trait 4</li>
<li>trait 5</li>
</ul>
<a class="more-less">Read More</a>
<p> end paragraph</p>
strong text
There's two main issues in your code. Firstly the ul.more is not a parent element of the clicked p, so parents().next() isn't the correct traversal logic to use. As the target element is a sibling of the one which raised the event, use siblings().
Secondly, you need to set display: block on the hidden ul. You can do this through CSS, on the .main class which you toggle.
Also note that you cannot nest p elements. I corrected this in the example below by converting the containing element to a div.
jQuery($ => {
$(".more-less").click(function() {
let $more = $(this).siblings('ul.more').toggleClass("main");
if ($more.hasClass('main')) {
$(this).text('Read Less');
} else {
$(this).text('Read More');
}
});
});
.more {
text-align: left !important;
display: none;
}
.more.main {
display: block;
}
.more-less {
color: #e43330 !important;
text-align: center;
float: left;
width: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<div>
First paragraph then cuts...
<p class="more">Second paragraph.</p>
<p><strong>Header key roles</strong></p>
<ul class="more">
<li>trait 1</li>
<li>trait 2</li>
<li>trait 3</li>
<li>trait 4</li>
<li>trait 5</li>
</ul>
<a class="more-less">Read More</a>
<p> end paragraph</p>
</div>
Try delete display: none; from more class

Sidebar With Expanding Menus. [Diagram Provided]

I have spent about an hour trying to find a solution that can work, however, none of them come close to my desired goal. I am not expecting someone to spend the time creating it for me (its a lot of work), but I want to know how I can achieve it. Links or js fiddle would be amazing.
So this sidebar I am working on. It should have three states.
The first and second state show up on table onwards.
The default state is when the sidebar is loaded.
The second state is what happens when the user clicks on one of the icon images that are seen in the first image. It now expands to show the additional navigation. (Ex. Icon says Friends, and the new menu that appears has a list of like 10 people).
The Third state only appears on mobile. It basically eliminated the icon sidebar seen in the Default State (first image)
I appreciate any advice on how to solve this. I have tried so many different things and none come close to what I want.
Is this what you are looking for?
var titles = $('.title');
titles.each(function() {
$(this).on('click', function() {
$(this).next().toggleClass('active')
})
});
$('.toggle').on('click', function() {
$('.sidebar').toggleClass('hide');
});
.toggle {
position: fixed;
z-index: 1000;
}
.sidebar {
position: fixed;
left: 0;
top: 0;
bottom: 0;
width: 200px;
padding-top: 20px;
border-right: 1px solid black;
}
.group {
margin-top: 16px;
}
.title {
cursor: pointer;
border-bottom: 1px dashed black;
}
.list {
max-height: 0;
overflow: hidden;
}
.list li {
margin-top: 4px;
}
.active {
max-height: 400px;
}
.hide {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="toggle">Button</button>
<div class="sidebar">
<section class="group">
<h3 class="title">Click me first.</h3>
<ul class="list">
<li>Link 1</li>
<li>Link 2</li>
<li>Link 3</li>
</ul>
</section>
<section class="group">
<h3 class="title">Maybe click me.</h3>
<ul class="list">
<li>Link 1</li>
<li>Link 2</li>
<li>Link 3</li>
</ul>
</section>
<section class="group">
<h3 class="title">Nope - click me!</h3>
<ul class="list">
<li>Link 1</li>
<li>Link 2</li>
<li>Link 3</li>
</ul>
</section>
</div>

Div toggle animation

Complete js newbie here, so sorry if im asking a stupid question :)
I have a navigation that toggles several divs, each link opens its own div, like this:
<div class="drawer" id="link1" style="display: none">First link content</div>
<div class="drawer" id="link2" style="display: none">Second link content</div>
<div class="drawer" id="link3" style="display: none">Third link content</div>
<nav>
<ul>
<li>Link 1</li>
<li>Link 2</li>
<li>Link 3</li>
<li>External link</li>
</ul>
</nav>
And the code that runs it:
$(document).ready(function () {
$('.menu').click(function () {
var $clicked = $(this)
$('.menu').each(function () {
var $menu = $(this);
if (!$menu.is($clicked)) {
$($menu.attr('data-item')).hide();
}
});
$($clicked.attr('data-item')).toggle();
});
});
It works well, but instead of simple showing/disappearing, i would wish to have slide up/down toggle effect on the divs when they are triggered.
I know there are slideUp and slideDown effects, but like i said, i am very new to all this and i cant make it work.
Fiddle is at http://jsfiddle.net/15kene5v/ and if anybody can help, that would be great.
Use slideUp and slideToggle instead of hide and toggle.
Updated Fiddle
$(document).ready(function() {
$('.menu').click(function() {
var $clicked = $(this)
$('.menu').each(function() {
var $menu = $(this);
if (!$menu.is($clicked)) {
// Use slideUp here
$($menu.attr('data-item')).slideUp('slow');
}
});
// Use sildeToggle here
$($clicked.attr('data-item')).slideToggle('slow');
});
});
nav ul {
margin: 0;
padding: 0;
background-color: #6DB4F3;
text-align: center;
}
nav ul li {
display: inline-block;
margin: 10px;
}
nav ul li a {
color: white;
text-decoration: none;
}
.drawer {
height: 100px;
background-color: darkorange;
color: white;
text-align: center;
position: relative;
}
.drawer:after {
content: 'close';
left: 0;
top: 0;
position: absolute;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.4.0/css/font-awesome.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div class="drawer" id="link1" style="display: none">First link content</div>
<div class="drawer" id="link2" style="display: none">Second link content</div>
<div class="drawer" id="link3" style="display: none">Third link content</div>
<nav>
<ul>
<li>Link 1
</li>
<li>Link 2
</li>
<li>Link 3
</li>
<li>External link
</li>
</ul>
</nav>
<div style="display:block">Content that gets pushed down</div>

Accordion with multiple links

I'm taking this CSS-Tricks article and converting it to a UL > LI instead of a DT > DD approach. I just want the pink box to reveal the sub-links when clicked.
For some reason though I cannot get it working. I've created a jsFiddle of it here (click the pink box):
//Accordion
(function($) {
var allPanels = $('ul.sub-level').hide();
$('.click-me').click(function() {
allPanels.slideUp();
alert('slide up');
// Problem line
$(this).parent().next().slideDown();
return false;
});
})(jQuery);
ul { list-style: none; padding:0; margin:0; width: 400px; }
ul li { position:relative; background: #fafafa; margin-bottom:3px; height:20px; }
ul li > ul { margin-left: 30px; background: #e3e3e3; }
.click-me { display:block; width: 20px; height: 20px; position: absolute; top:0; right:0; background: #e4f; cursor: pointer;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li>Link somewhere</li>
<li>Link somewhere</li>
<li class="test">
Link somewhere
<!-- I want to reveal accordion using this span tag -->
<span class="click-me"></span>
<!-- /end -->
<ul class="sub-level">
<li>Link 1</li>
<li>Link 2</li>
<li>Link 3</li>
<li>Link 4</li>
</ul>
<li>Link somewhere</li>
</li>
</ul>
http://jsfiddle.net/ndczc728/1/
The problem line is this (I think):
// Problem line
$(this).parent().next().slideDown();
Anyone?
You don't need to use parent. Also you have to remove fixed height from li elements:
//Accordion
(function($) {
var allPanels = $('ul.sub-level').hide();
$('.click-me').click(function() {
allPanels.slideUp();
// Problem line
$(this).next().slideDown();
return false;
});
})(jQuery);
ul {
list-style: none;
padding: 0;
margin: 0;
width: 400px;
}
ul li {
position: relative;
background: #fafafa;
margin-bottom: 3px;
}
ul li > ul {
margin-left: 30px;
background: #e3e3e3;
}
.click-me {
display: block;
width: 20px;
height: 20px;
position: absolute;
top: 0;
right: 0;
background: #e4f;
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li>Link somewhere
</li>
<li>Link somewhere
</li>
<li class="test">
Link somewhere
<!-- I want to reveal accordion using this span tag -->
<span class="click-me"></span>
<!-- /end -->
<ul class="sub-level">
<li>Link 1
</li>
<li>Link 2
</li>
<li>Link 3
</li>
<li>Link 4
</li>
</ul>
<li>Link somewhere
</li>
</li>
</ul>

how to hide dropdown menu if i click body any element?

How to close my DropDown menu if i click body element of outside dropdown menu .
Please give me suggestion .
My code is
$(document).ready(function(){
$(document).on('click', '.top-nav-head>li>a', function(){
$(this).siblings('ul').toggle().closest('.top-nav-head>li').siblings('li').find('ul').hide();
});
});
.top-nav-head{
list-style-type: none;
padding: 0;
margin: 0;
background:blue;
float: left;}
.top-nav-head>li{
float: left;
position: relative;
}
.top-nav-head>li > a{
color: #000;
padding: 0 10px;
display: block;
line-height: 40px;
font-size: 14px;
}
.top-nav-head>li > ul{
position: absolute;
display: none;
top: 100%;
left: 0;
min-width: 140px;
right: 0;
list-style-type: none;
padding: 5px 0 5px 0;
margin: 0;
background-color: red;
}
.top-nav-head>li > ul>li{
display: block;
}
.top-nav-head>li > ul>li > a{
display: block;
color:#white;
padding: 5px 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<ul class="top-nav-head">
<li>Home</li>
<li class="active">
Admin Module
<ul>
<li><a ui-sref="av-kw-questions.empty">Questions</a></li>
<li><a ui-sref="av-wbs">WBS Elements</a></li>
<li><a ui-sref="av-lbp">Lookback planning</a></li>
<li>Form</li>
<li>Plan Component</li>
</ul>
</li>
<li>
Project Management
<ul>
<li>Link 1</li>
<li>Link 2</li>
<li>Link 3</li>
<li>Link 4</li>
<li>Link 5</li>
</ul>
</li>
</ul>
You could attach an event handler to the document that will hide your drop down menus.
You would the need to stop the event bubbling when clicking on the menu items themselves:
$(document).ready(function () {
$(document).on('click', function () {
$('.top-nav-head > li > ul').hide();
});
$(document).on('click', '.top-nav-head>li>a', function (e) {
e.stopPropagation();
$(this).siblings('ul').toggle().closest('.top-nav-head>li').siblings('li').find('ul').hide();
});
});
JSFiddle
This will check if you have clicked on the element, just set your selector ("most" parent) and "hide" functionality:
$(document).mouseup(function (e)
{
var your_element = $('#your_element');
if(container.has(e.target).length === 0)
{
//hide your element
}
});

Categories