I have a reasonably complex list of Dynamic Div classes which contain various nexted divs to display shop content - the whole thing needs to have a hover state and be clickable (it currently has hover styles applied) and accessible.
I figure I can either approach this by -
1 - Make the containing Div into an Anchor link and style accordingly
2 - Nest an anchor tag within the div class and write a JS function to trigger a click on the anchor when the containing div is clicked.
Whats the thoughts on which is the correct approach?
I would definitely go with the wrapping <a> in that case you don't have to think about setting tabIndex=0, role=link and also you can skip adding the extra JavaScript to make the button clickable and binding the enter key for the same action as well.
Or if the "link" is not taking the user to another location and just show a modal window or some other fancy function you should wrap the <div> with a <button> in that case you can also skip binding the spacebar to the action too, as it is inherited. (But if you really can't do that you should add role=button to the wrapping <a>)
Now you can focus on styling and remember to use both :hover and :focus
It's fine to make the <div> clickable by adding an "onclick" handler. However, you should specify an ARIA "role" attribute (such as role="button" or role="link") as well as specify the "tabindex" attribute (tabindex="0") to make it possible to bring the element into focus when using the tab button on the keyboard.
Related
I have a expandable div element which is expanded when user clicks.
How can i make it accessible through screen readers.
Below is my code
HTML
<div class="expandable" (click)="expandItem()" attr.aria-expanded="isCollapsed">
Some content to show on expand
</div>
JS:
expandItem() {
this.isCollapsed = true
}
variable isCollapsed is set to false initially.
I might be showing my javascript ignorance but I haven't seen (click)="expandItem()" or attr.aria-expanded="isCollapsed" before. I have seen onclick="expandeItem()" and aria-expanded="false". But I'll ignore that aspect for now.
First off, your <div> has no semantic meaning so you'll need several ARIA attributes to fix that. But before you do that, consider the "First Rule of ARIA Use", which is essentially to not use ARIA. Use native semantic HTML elements as your first choice if possible.
I'd need more information on your scenario but consider using a real <button> instead of a <div>. It sounds like you might have a "disclosure widget".
If a real <button> is not used, then your <div> will need:
tabindex="0" (to allow keyboard focus to move to it)
a click handler (for mouse users)
a keyboard handler (for keyboard users to use space and enter to select it)
a role="button" so a screen reader announces the proper semantics
(I'm assuming your <div> has a label)
In addition to that, then you need to resolve your aria-expanded issue. In the onclick of the button (or div), just toggle the value of aria-expanded. Since that attribute is a "state" (instead of a "property"), changing its value will be announced automatically by screen readers.
I'm trying to use the bootstrap collapse plugin in such a way that a unique identifier is not required. Normally there is usually a single or a couple of collapsible elements on a page.
But my elements are generated dynamically and passing index keys is overkill.
What happens now is that if I toggle the collapse for element2, it will collapse element1. Obviously because they have the same ID.
Any way to achieve this without actually giving each collapsible element a unique id?
Here's a functional js fiddle:
http://jsfiddle.net/hhvrjnr3/
It can be done. First remove the data-target="#collapseExample" from the elements you want to collapse. Then add an extra class to your toggle button, I've added 'collapser'. That's not really needed, but it's nice to identify the toggle button. Then add some jQuery to do the toggling, in this case I am using next() to get the subsequent element to the toggle button which is your element you wish to collapse.
$('.collapser').click(function() {
$(this).next().collapse('toggle');
});
Example jsFiddle
I have a bunch of HTML fields logically separated as such: half the fields reside in: div id="general" and the other half reside in: div id="advanced"
What I'm trying to implement (and failing) is the following:
The fields in the general div to be shown (by default). A button with the caption "Advanced" shown. And the fields in the advanced div to be hidden.
When this button is clicked, the following should occur:
General section collapses hiding all it's fields
Advanced section expands showing all it's fields
Button caption is changed to "General".
Subsequent clicks toggles the above.
E.g. upon the next click, the advanced section now is hidden, general section now is shown, and button caption changes to "Advanced"
Notes: This seems trivial but being new to web front-end, I can't get this easily. If my div section is incorrect, then scrap it. I suspect I'm on the right track, and just need some jQuery code to collapse and expand divs.
Below are my attempts:
I used the Bootstrap collapse plugin with accordian markup, but this isn't what I want. It comes close though, but each section has a heading/button. I'd like one heading/button to toggle each section in an opposite manner.
I used the Bootstrap collapse plugin without the accordian markup, but same result as attempt 1 - two button again.
I tried using jQuery to do this dynamically, but can't get the logic (or syntax) correct.
I'm using Bootstrap, but happy to go with jQuery (or JavaScript) solution if it can't be done solely in Bootstrap with the collapse plugin.
You can do it using jquery by toggling a class on element which decides which fields to be shown.
for e.g. Take an outer div, and put general and advanced div inside outer div and show only the fields based on outer div class like advanced using css. And bind a button to toggle the class on the outer div.
Checkout JSFiddle here : http://jsfiddle.net/eqhw2mxx/2/
Check the JSFiddle :- JSFiddle
$("#advanced").addClass('hide');
$(".button").click(function(){
$("#advanced").toggleClass('hide');
$("#general").toggleClass('hide');
if($(this).attr("value") == "Advanced"){
$(this).attr("value","General");
}
else if($(this).attr("value") == "General"){
$(this).attr("value","Advanced");
}
});
I managed to get some js to work to my surprise, now I want to make it a little more complex which is way out of my expertise.
I have a button when clicked will reload a iframe that is on my page. I have multiple iframes all but 1 are hidden. Then I use jquery to display a different iframe and hidden the previous depending on the nav button clicked. e.g. "1-btn" (nav btn) tied to "1-win" (iframe), "2-btn" (nav btn) tied to "2-win" (iframe) etc. So when you click "2-btn", "1-win" iframe hides and "2-win" iframe is displayed. Now I want to change my code so this ties into my reload javasrcipt. Currently, my js only reloads 1 iframe via the iframe id. I want to change this id every time to a different iframe. This will allow my Reload btn to only reload the current iframe displayed and not any of the other that are hidden.
Here is my Reload js
function Reload () {
var f = document.getElementById('1-win');
f.src = f.src;
}
As you can see this reload script only works for iframe "1-win". When i click "2-btn" nav to display "2-win" iframe (and hides "1-win") the reload button still only works for "1-win". Therefore, I want it to also change. For e.g. when I click "2-btn" (nav) to display "2-win" iframe I want to change the Reload id to "2-win" also.
I was thinking of using onClick within my nav buttons which passed through the id of the iframe which that nav btn is tied to. However, I have no idea how to do this.
For full code see:
https://github.com/tmacka88/Service-Manager
Sorry if this doesn't make any sense, I cant think of an easier way to explain it.
Thanks
EDIT
This below answer may or may not still apply now that the problem has been better defined.
One approach you could try is having a hidden field on the page which contains a semi-colon separated list of the Id's of the iframes. E.g.
<input type="hidden" name="iframeids" value="1;2;3;4;5">
On the click event of your button, call some JavaScript which gets the value of the hidden field, takes the first token before the semicolon, and then reorganise the string. An example:
// Next value is 1
// Use 1 in your JS
// Put 1 to the end, next is now 2
<input type="hidden" name="iframeids" value="2;3;4;5;1">
You would contain the logic of re-arranging etc. in the JS function.
Now that the problem is better defined, we can work out a proper solution.
Here are some design considerations:
Ideally you do not want to manually add a new button for every iframe that you put on the page. Main reason being code maintenance. If you were to add a new iframe, or remove one, your code would not function correctly. Also the amount of mark-up required will be unnecessarily high
jQuery will make your life easier, although it's not required, it will cut out a lot of code. I can't stress enough the importance of knowing JavaScript basics first, but this is your responsibility to learn
For point 1, what we would like is a generic solution so that if you add more iframes, the buttons are added automatically. JavaScript is the way to do this (I'm assuming this is just HTML, not ASP.net or php or some other server side
Point 2 - jQuery will help with point 1.
Now we have this understanding, let's look at an outline of what we need to do:
In JavaScript, loop through the iframe tags on the page
For each iframe, generate a button using jquery, using the values like src and id in the iframe as attributes on the button
Add some click-event code to the button do define what it needs to do when clicked
Again using jQuery, add the newly created buttons to the DOM
This did the trick:
function Reload()
{
$("iframe").each(function()
{
if($(this).is(':visible'))
$(this).attr('src', $(this).attr('src'));
});
}
This is the problem page I'm developing.
Consider the leftmost column header, with header text "Undr." Here is the simplified html for that column header:
<th class="underlying" onclick="toggleColSelect(this);">
<img class='ad' onclick="toggleColSortOrder(this);">
Undr
</th>
The user can do two things in the column header:
select and deselect the column, by clicking the column header. EDIT: The column is selected when the column header has a yellow background; and unselected when the column header has a white background.
select ascending or descending sort on the column contents, by clicking the up/down-arrow image.
However, clicking the image also selects/deselects the column, which I don't want. When he clicks the image, I want to toggle the sort order only; I don't want to toggle the select on the column.
My JavaScript function toggleColSortOrder(); does indeed toggle only the sort order; but it seems the function to select the column also gets called (wrongly) when the user clicks the image.
What I've tried: thinking this might somehow be a manifestation of bubble-up at work, I tried all combinations of returning true, false and nothing in each of the two functions. None of this had any effect. I'd like to avoid hacking the JavaScript any further.
Question: how, by changing my html or css, can I prevent the function toggleColSelect(); being called when the user clicks inside the up/down-arrow image?
Your can cancel event-bubbling by adding
event.cancelBubble = true;
to your functions. See this fiddle: http://jsfiddle.net/fcyCz/
Here is my theory, since your <img> tag is INSIDE your <th> tag, you cannot click the <img> without first 'clicking' through the <th>. If there was a way to un-nest these two tags, I would then assume that their functions would be called separately. Possibly using a <div> to align your <img> over the correct spot. I am going to try to do live adjusting of what I just said using firebug and see (if it doesnt break the javascript) if it works, and I will report back.
Good luck.
As Tomalak points out, the click event for the <img> is bubbling up to the parent <th>, and so you must specify otherwise in your function. Also, add a call to event.stopPropagation() for the browsers which have deprecated cancelBubble.