2

I'm working with creating custom html tags/elements that will then be dynamically added via JavaScript/jQuery. My end goal is to create a custom element like <xt-vertical-layout height="30px" width="50px"></xt-vertical-layout> where height and width will set the rendered size. I have figured out how to create the custom elements and have custom attributes that can hold data, but I cannot seem to find a way to modify the rendering. To be clear, I am not having an issue with CSS height and width not working. My issue is that I could potentially have hundreds of the elements all with varying sizes that are unknown untill being injected into the DOM well after the document has loaded.

I had at first looked into CSS with attribute selectors but it does not seem to be able to carry the value of the attribute down into the CSS rule. Similarly I had looked into the attr() function of CSS but it seems this only works on content. I found a bit of documentation on this function being allowed for all attributes in CSS4 though I then read something saying CSS4 will not be released and instead CSS will begin to be updated per module and so it seems this has not made it into the current standard.

Any light that could be shed on this subject would be greatly appreciated. I feel like there is some way to do this but am not too sure how. To be clear though, I'm not wanting something like parsing through the markup with JavaScript/jQuery and modifying that element with $().css() or something like that, as this then modifies the actual markup. My desire is to have the markup unchanged and the attributes modify the rendering, similar to how the <img/> tag works.

EDIT: I do not mind doing this with JS/jQuery in the constructor for the custom element if it can be done there without modifying an inline style attribute, leaving the markup unchanged.

8
  • I don't think you can do this with CSS unless you consider inline style. You are obliged to do some JS I guess Commented Feb 8, 2019 at 0:02
  • as in style="height:30px"? Commented Feb 8, 2019 at 0:03
  • yes, which is trivial in this case but you have inline style and you have to deal with specificity issue if you want to apply another CSS later Commented Feb 8, 2019 at 0:07
  • Also, the JS you speak of, are you referring to modifying the inline style attribute, or in the constructor for the custom element? If it is the second I would love (and actually rather) that. Commented Feb 8, 2019 at 0:16
  • 1
    well with JS you can do a lot of things. The first think would be to change the style attribute but we can do something else like generating unique CSS for this element using a random class/ID Commented Feb 8, 2019 at 0:17

2 Answers 2

4

You would normally handle this in your CustomElement's class connectedCallback, where you will be able to access the node as this, and its DOM methods like getAttribute() if it inherits from HTMLElement.

class VerticalLayout extends HTMLElement {
  constructor() {
    super();
  }
  connectedCallback() {
    this.style.width = this.getAttribute('width');
    this.style.height = this.getAttribute('height');
  }
}
customElements.define('xt-vertical-layout', VerticalLayout);

// dynamically inserted
const elem = document.createElement('xt-vertical-layout');
elem.setAttribute('width', '25px');
elem.setAttribute('height', '25px');
document.body.append(elem);
xt-vertical-layout {
  border: 1px solid;
  display: inline-block;
}
<xt-vertical-layout height="30px" width="50px"></xt-vertical-layout>

<xt-vertical-layout height="50px" width="150px"></xt-vertical-layout>

<xt-vertical-layout height="10px" width="50px"></xt-vertical-layout>

And if you really do not want to modify the serialized DOM, then you can append a stylesheet inside the shadowDOM of your elements, and set a rule there. But note that doing so, you will loose support for older browsers as this feature can't be polyfilled.

class VerticalLayout extends HTMLElement {
  constructor() {
    super();
  }
  connectedCallback() {
    const shadow = this.attachShadow({mode: 'open'});
    const style = document.createElement('style');
    style.textContent = `:host {
  width: ${ this.getAttribute('width') };
  height: ${ this.getAttribute('height') };
}`;
    shadow.append(style);
  }
}
customElements.define('xt-vertical-layout', VerticalLayout);

// dynamically inserted
const elem = document.createElement('xt-vertical-layout');
elem.setAttribute('width', '25px');
elem.setAttribute('height', '25px');
container.append(elem);

console.log(container.innerHTML);
xt-vertical-layout {
  border: 1px solid;
  display: inline-block;
}

.as-console-wrapper {max-height: 120px !important;}
<div id="container">
<xt-vertical-layout height="30px" width="50px"></xt-vertical-layout>

<xt-vertical-layout height="50px" width="150px"></xt-vertical-layout>

<xt-vertical-layout height="10px" width="50px"></xt-vertical-layout>
  
</div>

Sign up to request clarification or add additional context in comments.

9 Comments

What I am wanting is to be able to do this without modifying the markup itself. When doing it your way, the markup gets the inline attribute style added to it. A CSS rule that pulls the value of the attribute could do this but that only seems to be possible for the content property.
@Xandor you could append a stylesheet in the shadowDOM of your element if you are ok with using shadowDOM, but you'll then loose support for a lot of old browsers (this can't be polyfilled). Why isn't it ok to have the style property get changed?
Losing support for old browsers is not much of a concern for me at the moment, what I am working on is experimental in itself anyways. Not changing the markup is not a deal breaker for me, but it would be greatly preferred. Essentially I am trying to write a markup language that would fit into a system I have already built that runs out of a web browser. The idea is that people will be able to develop for it. With that in mind, sharing/observing other code would be more intuitive to people first learning it if the markup was left unchanged.
With that being said, I think this shadowDOM is going to be the closest thing to behind the scenes I will get for now. Much appreciated!
In your position, I would rather keep the markup and the DOM as two separated things. Users provide markup, and your page generates DOM. No need to worry about modifying the DOM as long as you keep the markup clean (like in a string variable). All it takes is some UI more appealing than the browser's dev-tools (depending on your targeted user-base, it will be more or less easy).
|
0

Custom tags will have a display of inline which cannot have width and height. You need have a display of block or inline block.

addContent('Here is some content', 200, 50);

function addContent(content, width, height) {
  const elm = document.createElement('xt-vertical-layout');
  elm.setAttribute('style', `width: ${width}px; height: ${height}px;`);
  elm.innerText = content;
  document.body.append(elm);
}
xt-vertical-layout {
  display: inline-block;
  color: white;
  padding: 5px;
  background-color: red;
}

3 Comments

I apologize if I didn't explain it well enough in my question but this is not at all my issue. My problem is that I will have multiples of these custom tags and I'm wanting to set the width and height by using inline width and height attributes. The problem is that I will not know the height and width needed until the element is loaded. They won't all have the same size and will vary greatly. I can't achieve this with static CSS rules.
Edited to be dynamic
Again, this does not answer my question at all. I want to be able to have this effect without modifying the markup (i.e. I do not want an inline style attribute added once processed) instead I want this done more behind the scenes.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.