Consider the following example:
let template = document.querySelector('.quote-template').innerHTML;
let shadowElement = document.querySelector('.quote-app');
let shadow = shadowElement.attachShadow({
mode: 'open'
});
shadow.innerHTML = `
<style>
.quote {
font-family: Arial;
font-size: 20px;
padding: 25px 40px;
background-color: #000;
font-weight: 300;
line-height: 24px;
color: #fff;
margin-bottom: 15px;
}
.quote:focus {
color: red;
}
</style>
${template}
`;
console.log(document.querySelector('.quote-app').shadowRoot.delegatesFocus)
.quote-app:focus {
outline: 2px dotted red;
}
<template class="quote-template">
<div class="quote">
Use mouse right click on the test button and you will see red outline on the shadow root.
<button>Test focus</button>
</div>
</template>
<div class="quote-app"></div>
As you can notice, when the "test focus" button gets focus, the parent shadow host also get :focus styles. Now, the MDN docs say that
If true(delegatesFocus), when a non-focusable part of the shadow DOM is clicked, the first focusable part is given focus, and the shadow host is given any available :focus styling.
It doesn't say anything about when a focusable part gets focused. Here in my scenario delegatesFocus is false, why does the shadow host get the :focus styling?
P.S: The observed behaviour contradicts google web.dev's documentation. They mention:
If you were to set delegatesFocus: false, here's what you would see instead:
The outer black dotted outline turns into red in reality, contradicting the image.
Related
Update
I'd modded the CSS given by David Thomas a bit. Its now a banner.
.div.popular::before {
/* setting the default styles for
the generated content: */
display: block;
width: 10em;
height: 2em;
line-height: 2em;
text-align: center;
background: #F60;
color: #fff;
font-size: 1.4rem;
position: absolute;
top: 30px;
right: 0px;
z-index: 1;
}
I would like to make a folded corner sort of like in this post: Folded banner using css
--- Original post ---
Let me first explain what I'm trying to do. I'm trying to give some post some extra attention by making a little circle with some call-to-action text in it.
But I only want this to trigger when a div has a specific class.
So if the div the class populair or sale I would like to have a little circle show up on that post. This script what I am using right now.
$(document).ready(function($){
if($("#front-page-items").hasClass('populair')){
$(".populair-div").show();
}
if($("#front-page-items").hasClass('sale')){
$(".sale-div").show();
}
});
And this HTML:
<div class="populair-div" style="display:none;">
<strong>Populair</strong>
</div>
<div class="sale-div" style="display:none;">
<strong>Sale</strong>
</div>
But this only show's the populair-div and not the other one. I'm guessing my script is wrong. Should I use else for all the other call-to-action classes?
$(document).ready(function($){
if($("#front-page-items").hasClass('populair')){
$(".populair-div").show();
}
else($("#front-page-items").hasClass('sale')){
$(".sale-div").show();
}
else($("#front-page-items").hasClass('Free')){
$(".free-div").show();
} // and so on
});
Is there someone that could help me out? Also is it possible to echo the div so I don't have to write a whole div for every call-to-action div?
For something like this, where the displayed text is explicitly linked to the class-name of the element it's easiest to use CSS and the generated content available, effectively hiding the elements you don't wish to show by default and then explicitly allowing elements you want to show, along with the generated content of those elements (using the ::before and ::after pseudo-elements:
div {
/* preventing <div> elements
from showing by default: */
display: none;
}
div.populair-div,
div.sale-div {
/* ensuring that elements matching
the selectors above (<div>
elements with either the 'sale-div'
or 'populair-div' class-names
are shown: */
display: block;
}
div.populair-div::before,
div.sale-div::before {
/* setting the default styles for
the generated content: */
display: block;
width: 4em;
height: 4em;
line-height: 4em;
text-align: center;
border: 3px solid transparent;
border-radius: 50%;
}
div.populair-div::before {
/* setting the text with the
"content" property: */
content: "Popular";
/* providing a specific colour
for the generated contents'
border: */
border-color: #0c0;
}
div.sale-div::before {
content: "Sale";
border-color: #f90;
}
/* entirely irrelevant, just so you can
see a (slightly prettified) difference
should you remove the default display
property for the <div> elements: */
code {
background-color: #ddd;
}
em {
font-style: italic;
}
<div class="neither-popular-nor-sale">
<p>
This element should not be shown, it has neither a class of <code>"populair-div"</code> <em>or</em> <code>"sale-div"</code>.
</p>
</div>
<div class="populair-div">
</div>
<div>Also not to be shown.</div>
<div class="sale-div">
</div>
You can use toggle function for this. It will be shorter and clearer.
Display or hide the matched elements.
Note: The buttons is for tests.
$(document).ready(function($){
init();
});
function init() {
$(".populair-div").toggle($("#front-page-items").hasClass('populair'));
$(".sale-div").toggle($("#front-page-items").hasClass('sale'));
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="front-page-items" class="populair sale"></div>
<div class="populair-div">populair-div</div>
<div class="sale-div">sale-div</div>
<hr />
<button onclick="document.getElementById('front-page-items').classList.toggle('populair');init()">toggle populair</button>
<button onclick="document.getElementById('front-page-items').classList.toggle('sale');init()">toggle sale</button>
so I was just messing around with some Javascript for learning purposes and noticed a weird behavior.
I created buttons that, on click, create a duplicate of themselves. The first newly created button has a left margin that I cannot find an explanation for. Does anyone know the reason for that and how to remove that unwanted spacing?
var makeNewBtn = function() {
var newBtn = document.createElement('button');
newBtn.className = 'btn';
newBtn.textContent = 'Click Me';
newBtn.onclick = makeNewBtn;
document.getElementById('buttons').appendChild(newBtn);
};
document.getElementsByClassName('btn')[0].onclick = makeNewBtn;
body {
padding: 25px;
}
.btn {
height: 100px;
width: 100px;
background: beige;
font: 18px Arial;
border: 0;
border-radius: 10px;
outline: none;
}
<div id="buttons">
<button class="btn">Click Me</button>
</div>
result here
There are two issues here:
You have a space after the first button in the HTML
Remove the spaces between the <div> and the <button>.
<div id="buttons"><button class="btn">Click Me</button></div>
Here's a great article about the many ways to "fight" against this space: https://css-tricks.com/fighting-the-space-between-inline-block-elements/
You didn't set margin/padding for the button styles
If not explicitly set, the browser may use a margin/padding, or inherit these from another style.
.btn {
padding: 0;
}
Here is a working fiddle: https://jsfiddle.net/1cg6uvdh/ I changed the background color to red so that the gaps are more visible.
I am trying to create a div and show a timeout message in there. But it actually distorts other parts of Page. For eg see below. Session Timed out is the div with the message.
Now I don't want this to happen. PFB the JQuery code I am using to create this Div
function ShowSessionTimeOutDiv() {
var styler = document.createElement("div");
styler.setAttribute("style","font-size:15px;width:auto;height:auto;top:50%;left:40%;color:red;");
styler.innerHTML = "<b><i>Session TimedOut, Please refresh the Page</i></b>";
document.body.appendChild(styler);
var currentDiv = $('#GoToRequestControl1_UpdatePanel1').get(0);
currentDiv.parentNode.insertBefore(styler,currentDiv) ;
}
Am I missing something here? The Part in which this div is being displayed is coming from Master Page.
Have you tried the position:fixed styling on it in css, i did that on one of my websites and it didn't distort anything.
A page has a natural flow of its elements based on the default display rules specified by the W3C. When you add a div in between other elements it naturally affects the layout of the page; the positions of the other elements.
In order to drop in a new element without it affecting other elements you have to either reserve space for it, or take it out of the normal page flow.
There are a couple of ways to take an element out of the flow — you can float it, float:left or float:right, which is great, for example, to stack blocks on the left (instead of top-down) and let them wrap to new rows as available width changes. Using a flex layout gives you a lot of control also. But in this case of one thing popping up, changing the positioning of the new element is the most straightforward and can let you put the block exactly where you want it.
I have a demonstration and full explanation in a fiddle showing several examples along the way to getting what you want.
Basically, styling is needed to reposition the timeout message element that you're inserting. Styling is better done with CSS styles, compared to adding a bunch of inline styles. If I put my timeout popup message in a "messagebox" I can make a class for it.
/* Your styles, plus a couple extra to make the example stand out better */
div.messagebox {
font-size: 16px;
width: auto;
height: auto;
top: 40%;
left: 30%;
background-color: white;
border: 2px solid black;
}
Likewise, style the message itself with a class, instead of using inline styles and the deprecated presentational tags <b> and <i>.
/* I want the message in a messagebox to be bold-italic-red text. */
div.messagebox .message {
color: red;
font-style: italic;
font-weight: bold;
}
The big difference is that we will change the positioning of the element from the default static to instead use absolute positioning:
/* I don't really recommend a class called "positioned".
A class should describe the kind of thing the element *is*
not how it *looks*
*/
div.messagebox.positioned {
position: absolute;
width: 40%;
padding: 1.5em;
}
/* The container of the positioned element also has to be positioned.
We position it "relative" but don't move it from its natural position.
*/
section#hasposition {
position: relative;
}
The term "absolute" is tricky to learn ... the element being positioned is given an absolute position within its container, in a sense it's positioned relative to its container... but what position:relative means is relative to its own natural position, so it's easy to get confused at first over whether you want absolute or relative positioning.
Putting it all together, we have some basic HTML that represents major portions of a page — a real page will have far more, but those should be contained within some top-level containers. This shows only those top-level containers.
Then we have some javascript that will add the new element at the appropriate time. Here I just call the function to add it after a delay created with setTimeout(). I'm using full-on jQuery since you're using some in your example, and it makes the javascript more portable and more concise.
function ShowSessionTimeoutStyled() {
var styler = $('<div>').addClass('messagebox').addClass('positioned');
styler.html('<span class="message">The Session Timed Out</span>');
$('#hasposition .above').after(styler);
}
// wait 6 seconds then add the new div
setTimeout(ShowSessionTimeoutStyled, 6000);
div.messagebox {
font-size: 16px;
width: auto;
height: auto;
top: 20%;
left: 20%;
background-color: white;
border: 2px solid black;
}
div.messagebox .message {
color: red;
font-style: italic;
font-weight: bold;
}
div.messagebox.positioned {
position: absolute;
width: 40%;
padding: 1.5em;
}
section#hasposition {
position: relative;
}
/* also style some of the basic parts so you can see them better in the demonstration */
section.explanation {
margin: 1em 0.5em;
padding: 0.5em;
border: 1px solid gray;
}
.demonstration {
margin-left: 1em;
padding: 1em;
background-color: #e0e0e0;
}
.demonstration .above {
background-color: #fff0f0;
}
.demonstration .middle {
background-color: #f0fff0;
}
.demonstration .below {
background-color: #f0f0ff;
}
.demonstration footer {
background-color: white;
}
p {
margin-top: 0;
padding-top: 0;
}
section {
font-family: sans-serif;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section class="explanation">
<p>Here, a div is added dynamically, after the "basic part above", but the added div is <em>positioned</em>. You can see the other content isn't affected.</p>
<section class="demonstration" id="hasposition">
<div class="above">Basic part above</div>
<div class="middle">Middle part</div>
<div class="below">Part Below</div>
<footer>This is the page footer</footer>
</section>
</section>
I highly recommend the site Position Is Everything for articles and tutorials on positioning. Some of its other content is outdated — who needs to make PNGs to do drop-shadows any more? — but the way positioning works hasn't changed.
When you open this page (see Live demo) with Chrome :
<span id="myspan" contenteditable=true></span>
CSS :
#myspan { border: 0; outline: 0;}
JS :
$(myspan).focus();
the contenteditable span has focus (you can start to write things and you will see that it already had focus), but we don't see the "I" edit cursor.
How to make that this cursor is displayed ? (Remark : outline:0 is needed, as well as the fact that the span is empty even with no white space).
Note : With Firefox, the cursor is displayed.
The problem is that spans are inline elements. Just add display:block; to your CSS and it will fix the problem.
$(myspan).focus();
#myspan {
border: 0;
outline: 0;
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<span id="myspan" contenteditable=true></span>
I added padding to the left and the cursor appears.
#myspan
{
border: 0;
outline: 0;
min-width: 100px;
height: 30px;
padding-left: 1px;
}
Demo in jsFiddle
.cont_edit {
outline: 1px solid transparent;
}
This just has to do with the way an empty ContentEditable area is rendered. To prove it's not about the focus, add some text to your editable div, and then delete it. When the last character is gone, the cursor will disappear
From the question Setting the caret position to an empty node inside a contentEditable element
The selection/range model is based around indexes into text content, disregarding element boundaries. I believe it may be impossible to set the input focus inside an inline element with no text in it. Certainly with your example I cannot set focus inside the last element by clicking or arrow keys.
It almost works if you set each span to display: block, though there's still some highly strange behaviour, dependent on the existence of whitespace in the parent. Hacking the display to look inline with tricks like float, inline-block and absolute position make IE treat each element as a separate editing box. Relative-positioned block elements next to each other work, but that's probably impractical.
You could also try adding a zero-width character like
document.getElementById('myspan').focus();
#myspan {
border: 0;
outline: 0;
}
<span id="myspan" contenteditable="true"></span>
The solution was to change <span> to <div> (I've seen that this solves many contenteditable problems in other questions here and there) + to add a min-width.
Indeed, with the following code, the size of the <div> would be 0px x 18px ! That explains why the caret (edit cursor) would be hidden !
HTML
<div id="blah" contenteditable=true></div>
CSS
#blah {
outline: 0;
position: absolute;
top:10px;
left:10px;
}
JS
$("#blah").focus();
Then, adding
min-width: 2px;
in the CSS will allow the caret to be displayed, even with Chrome : http://jsfiddle.net/38e9mkf4/2/
The issue I faced on Chrome v89.0.4389.90 was that contenteditable fields would sometimes show the blinking caret on focusin and sometimes not. I noticed it always blinks when there's already content in the field before focusing. It's when there's no content that the sometimes will/won't behavior occurs.
At first, I thought there must be some conflicting event handler that's erratically taking focus away. I disabled all my event binds and timers. Still the same erratic behavior. Then I thought it might be some conflicting CSS, so I disabled all stylesheets. At least now the behavior was consistent: the caret blinks 100% of the time when the field has content; the caret does not blink 100% of the time when the field has no content.
I enabled binds and stylesheets again. My div was already set to display: block; with min-width, min-height, and padding set in the final computed style set. None of the other answers here worked. I do have a placeholder on :empty:before that was a possible culprit. I commented that out. Now the behavior was consistent again, same as if the stylesheet was off. Oddly enough, the runnable snippet on SO works with the same computed CSS stack. I want to keep the placeholder, so it requires further research with my actual codebase...
The only solution I could get to work 100% of the time with my current issue involved forcibly placing the caret inside empty fields by creating a blank space and removing it immediately afterwards. Best I can do for a workaround until debugging the root cause.
//force caret to blink inside masks
let force_caret = function() {
if (!this.textContent) {
this.textContent = ' ';
let r = document.createRange(),
s = window.getSelection();
r.setStart(this.childNodes[0], 0);
r.collapse(true);
s.removeAllRanges();
s.addRange(r);
this.textContent = '';
}
}
//binds
let els = document.querySelectorAll("[contenteditable]");
for (let i = 0; i < els.length; i++) {
els[i].addEventListener('focusin', force_caret, false);
}
/* styles irrelevant to the issue, added for visual assist */
:root {
--b-soft: 1px solid silver;
--bs-in: inset 0 1px 3px rgba(0, 0, 0, 0.3), 0 1px rgba(255, 255, 255, 0.1);
--c-soft: gray;
--lg-warm: linear-gradient(30deg, rgb(254, 250, 250), #eedddd);
}
body {
font-family: system-ui, -apple-system, -apple-system-font, 'Segoe UI', 'Roboto', sans-serif;
}
[contenteditable] {
outline: initial;
}
[contenteditable][placeholder]:empty:before {
content: attr(placeholder);
color: var(--c-soft);
background-color: transparent;
font-style: italic;
opacity: .5;
font-size: .9em;
}
.input {
border-bottom: var(--b-soft);
padding: .2em .5em;
}
.input_mask {
display: flex;
align-items: baseline;
color: var(--c-soft);
}
.mask {
box-shadow: var(--bs-in);
border-radius: .2em;
background: var(--lg-warm);
font-weight: 500;
border: 1px solid transparent;
text-transform: uppercase;
/* styles possibly relevant to the issue according to other proposed solutions */
margin: 0 .4em .1em .4em;
padding: .2em .4em;
min-width: 3em;
min-height: 1em;
text-align: center;
}
<div data-type="tel" data-id="phone" class="input input_mask">
<span>+1 (</span>
<div maxlength="3" contenteditable="true" placeholder="111" class="mask"></div>
<span>)</span>
<div maxlength="3" contenteditable="true" placeholder="111" class="mask"></div>
<span>-</span>
<div maxlength="4" contenteditable="true" placeholder="1111" class="mask"></div>
<span>x</span>
<div maxlength="5" contenteditable="true" class="mask"></div>
</div>
Add a CSS style of
min-height: 15px;
you may also need
display: block;
to your contenteditable="true" tag
For me setting it content of contenteditable div to <br> works. I tried setting it to nbsp; but that creates extra character space in the div before i start editing. So, i choose this:
<div id="blah" contenteditable=true><br></div>
over:
<div id="blah" contenteditable=true>nbsp;</div>
Hope this helps.
I use Chrome and your Code works fine.
Try to use cursor: text; in your CSS. See here
I have these buttons on the side of my page, and a main content area taking up the better part of the page.
What I am trying to do is get the button I click to change the main content to a div containing the corresponding information. This is very hard to find, perhaps because I am searching by the wrong terms, and I have covered a good portion of stackoverflow without much luck.
I have though about absolutely positioning the divs and using a script to change the z-index of the the divs to the highest amount using a "=+1" type situation, but I could see that getting messy.
I have considered adapting a script I have that replaces part of an image file name in order to change a main picture on a page to a larger version of the image corresponding to a thumb name, though this script targets file names so it isn't going well.
I have also tried something along the lines of:
"id of button" onclick function = "main content class" change id to "corresponding div"
only in javascript talk, and this isn't working at all so I can only assume that I am either looking at it wrong or I have some messed up in the code.
$('#tabhead1').click(function() {
document.getElementByClassName("maintab").id = "tabs1";
});
This is driving me crazy and I would really appreciate some ideas. I tried to leave it free formed so that noone gets hung up on anyone solution.
**** Just to clarify, I have 5 divs id'd at #tabhead1, #tabhead2, #tabhead3, etc. and 5 content divs classed as .maintab, and id'd as tabs1, tabs2, tabs3, etc. I need the first content div to show automatically, and for that div to change based on the button clicked. at the moment all content divs are set to display: none; except the first one.
For each button, add a data attribute related to the corresponding <div>
for example
<button id="tabhead1" data-content="tabs1" >first Tab</button>
apply a common class for the tabs, for example .tab
Then you can do the following
$('button').click(function(){
var contentId = $(this).data('content'); // get the id of corresponding tab
$('.tab').hide(); // hide all tabs
$('#'+contentId).show(); //show the corresponding tab
});
You are using getElementbyClassName which does not exists. Use:
document.getElementsByClassName("maintab")[0].id = "tabs1";
// Get all elements to match classname + get first element from array
And for the rest, I don't know why you want to add id with JS? Why not just add them to your HTML?
Try this
$('#tabhead1').click(function() {
// get element with class 'maintab' and replace its content with that of another tab
$(".maintab").html($(".tabs1").html());
});
To expand a little on the demo I posted in the comments earlier:
This uses a method very similar to #tilwin-joy, so I guess we were of like mindedness. There are a couple of small differences that I would point out:
jQuery:
$('button').on('click', function () {
var button = $(this);
var target = button.data('target');
button.prop('disabled', true).siblings().prop('disabled', false);
$(target).show('slow').siblings().hide();
});
This uses siblings to hide the other content (one less pass at the DOM).
I suggest just setting your data value with the id hash in the markup, I think it's a bit clearer to read and follow (IMHO) in both the script and markup.
This script also sets the current button to be disabled when clicked. The benefit of this is that you can use the disabled property to style up your buttons, and even if you don't style them it gives a visual cue to the user as to which tab content is currently displayed. Check out the demo to see how this can be used for styling purposes.
HTML: (I stripped some of the unneeded ids from what you described as your markup).
<div class="tabhead">
<button data-target="#tabs1" disabled="true">Content 1</button>
<button data-target="#tabs2">Content 2</button>
<button data-target="#tabs3">Content 3</button>
<button data-target="#tabs4">Content 4</button>
<button data-target="#tabs5">Content 5</button>
</div>
<div class="maintab">
<div id="tabs1">
<img src="http://placehold.it/350/e8117f/fff&text=Image+1" alt="Image 1" />
<p>This is the content of tabs1.</p>
</div>
<div id="tabs2">
<img src="http://placehold.it/350/9acd32/fff&text=Image+2" alt="Image 2" />
<p>This is the content of tabs2.</p>
</div>
<div id="tabs3">
<img src="http://placehold.it/350/9400d3/fff&text=Image+3" alt="Image 3" />
<p>This is the content of tabs3.</p>
</div>
<div id="tabs4">
<img src="http://placehold.it/350/ffd700/fff&text=Image+4" alt="Image 4" />
<p>This is the content of tabs4.</p>
</div>
<div id="tabs5">
<img src="http://placehold.it/350/1e90ff/fff&text=Image+5" alt="Image 5" />
<p>This is the content of tabs5.</p>
</div>
</div>
CSS: Not needed - just to give you an idea of how you can style the elements to look like tabs.
/*This sets all but the first tab to hidden when the page is loaded*/
.maintab>div:not(:first-child) {
display: none;
}
/*The rest is just to style the elements to look like tabs*/
body {
background-color: #eaeaea;
}
.maintab, .tabhead {
text-align: center;
margin:0 20px;
font-family: sans-serif;
}
.maintab {
border: 1px solid #1e90ff;
border-top: none;
padding-top: 20px;
background-color: #fff;
}
.tabhead {
border-bottom: 1px solid #1e90ff;
position: relative;
margin-top: 20px;
}
button {
background-color: #ccc;
padding: 10px;
border: 1px solid #999;
border-bottom: none;
-webkit-border-top-left-radius: 4px;
-webkit-border-top-right-radius: 4px;
-moz-border-radius-topleft: 4px;
-moz-border-radius-topright: 4px;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
color: #999;
font-size: 14px;
cursor: pointer;
position: relative;
top: 2px;
}
button:disabled {
background-color: #fff;
border-color: #1e90ff;
color: #1e90ff;
top: 3px;
padding-top: 11px;
cursor: not-allowed;
z-index: 10;
}