Stencil Component - use querySelector() to select element within the shadow dom - web-component

I'm creating a component that is wrapping a canvas library I've been using, to make it portable between a few of my applications and scope it's functionality/style to be consistent across applications.
The problem is, part of the library requires me to pass the canvas element as a parameter for a class.
Is it possible to select the element from inside the stencil class? The only way I've managed to accomplish it so far is by turning off the shadow DOM, which defeats the purpose a little bit.

To access elements in the Shadow DOM you have to use the shadowRoot property:
#Element() el;
// ...
const canvas = this.el.shadowRoot.querySelector('canvas');

After much searching (before asking) and very little searching (after asking) I've found an answer. Apparently refs are usable here.
<canvas ref={(el) => {this.canvas = el}}>
</canvas>

Related

Using existing CSS selectors to apply styles across the Shadow DOM to custom elements

This question likely has no single direct answer, but hopefully will lead to some best practices or common patterns to use when adapting an existing styles framework to new web component development.
For my case, I have a component <custom-avatar>, and it's all set up properly with self-contained styles and functionality, everything is just peachy.
In certain use cases, the application display needs to stack avatars, just one slightly overtop one other at a diagonal, and the pattern I'm following is using a simple component <custom-composite-avatar>. All this does is wrap the slotted content in a <div> with the correct styling class, but key aspect is retaining the composability for flexible re-use, like so:
<custom-composite-avatar>
<custom-avatar title="first"></custom-avatar>
<custom-avatar title="second"></custom-avatar>
</custom-composite-avatar>
The tricky bit lies in the styles, which are imported from a monorepo that provides the same BEM-ish CSS and component CSS modules to other flavors of the component library like React, Vue, etc. I have the avatar and composite-avatar styles imported just fine, but forcing the intended overlap display is defined with the hierarchical selector .my-composite-avatar.my-composite-avatar--medium .my-avatar {}
So with .my-composite-avatar class applied to the div wrapper within <custom-composite-avatar> and the .my-avatar class applied to the wrapper within the <custom-avatar> and it's own Shadow DOM, that parent/child CSS selector is no good.
I doubt there is a silver bullet for this, but this seems like it will be a rather common scenario as more people migrate to Web Components while using existing styling systems. What approach makes the most sense to ensure that the composite component remains composable, and adaptation of existing selectors pain-free (or at least easy to communicate to other devs)? can this be solved with ::host or ::slotted, or will these cases require significant re-work?
Thanks for reading, your ideas are appreciated!
I would advice to become good friends with CSS properties
because they trickle down into shadowDOMs following CSS selectors.
CSS Custom Properties(variables)
and getPropertyValue
and setProperty if you want to be brutal and make Custom Elements change the outside world.
example
I have an <SVG-ICON> element taking configuration from attributes OR CSS properties
with my favorite lines of code:
let val = this.getAttribute(attr)
||
getComputedStyle(this)
.getPropertyValue("--svg-icon-" + attr)
.replace(/"/g, "")
.trim();
Allows for your standard attribute configuration:
<svg-icon name="configuration" fill="grey"></svg-icon>
But more powerful (simplified example):
<style>
body {
--svg-icon-fill: "grey";
}
svg-icon[selected] {
--svg-icon-fill: "green";
}
</style>
<svg-icon name="messages" selected></svg-icon>
<svg-icon name="configuration"></svg-icon>
CSS = Custom String Scripting
It doesn't often happen, but sometimes the simplest code makes me very happy.
There is no Styling restriction!
These 2 lines allow any String you want in CSS properties:
.replace(/"/g, "")
.trim();
Example
<style>
[name*="globe"] {
--svg-icon-tile: "rect:0,0,24,24,0,fill='blue'";
--svg-icon-stroke: white;
}
</style>
<svg-icon name="feather-icons-globe"></svg-icon>
The --svg-icon-tile has nothing to do with CSS, it is read (and parsed) by the <SVG-ICON> connectedCallback() code to generate a SVG background/tile for all icons named globe.
The double-quotes aren't required, but without them your IDE will complain about invalid CSS.
Have fun coding... you will pull some hairs when you start with calc() in your CSS properties...
But you can take 'CSS' to another level.
PS.
And monitor the future of ConstructAble StyleSheets aka ConstructIble StyleSheets aka Constructed Sheets aka AdoptedStyleSheets:
https://developers.google.com/web/updates/2019/02/constructable-stylesheets
https://chromestatus.com/feature/5394843094220800
iconmeister

should i use media queries for responsive design with react?

I want to make a responsive website using react, should i use media queries for change layout and set display to 'none' for some components in mobile ( like regular html and css ), or do that in-react and don't render that component rather than don't display it using css ?
for example, for a menu, if user clicked on the menu button, change display property of menu from 'none' to 'block'
<ul id="menu">
<li>one</li>
<li>one</li>
</ul>
toggle the 'open' in the classList of the DOM Node
and in the css
.menu li {
display: none;
}
.menu.open li {
display: block;
}
or like this,
use state and if user clicked on the menu button, change the state and make react to render the menu
[open,setOpen] = useState(false);
open?<Menu />:'';
which one is a better approach ? which one is recommended
and one more question, using 'refs' for accessing the DOM nodes in react is better than use traditional document.getElementById() ?
My initial reaction is that you probably aren't building anything that absolutely requires the most performant solution, so hiding an element via CSS versus eliminating it from the DOM via React is not going to matter much in the long run. My recommendation is do whatever you can to get your project complete and then worry about performance if your use-case warrants it.
With regards to your specific example, it is probably better to just toggle the element's existence with React versus applying a class to toggle the display property. My reasoning for that is because both operations will require a DOM manipulation (React would have to either add the list element or it would have to update the className value). Using a CSS class to toggle the display will also have a secondary task of applying the new display value which causes another reflow of the content.
React solution: Update DOM to insert new node.
CSS solution: Update DOM to add className. Reflow content based on new display property.
Regarding your second question about $refs...
Using $refs will be better than document.getElementById. The $refs object maintains an in-memory reference to HTML nodes that need to be manipulated. document.getElementById will require traversing the DOM tree to find the element, where as using $refs simply looks up the node via a named property.
If it's possible to do in CSS, always use CSS. JS is expensive than CSS in terms of loading and rendering. For your requirement, you need layout change depending on the device it's loaded. So use media queries and CSS Grids to do that without using JS.
Refs is the react way to get DOM element. So please use that instead of using methods like document.getElementById().

css variables :root vs :host

Just starting with webdevelopment (coming from android)
in my project I tried to assign variables as in many tutorial is mentions with help of ":root" :
:root {
--accentColor: #20a8d8;
--primary: #96a1a5;
--secondary: #415a72;
--bgColorrr:#1e2e38;
}
But that did not work at all.
After changing it to ":host" it work though - can someone please explain what is the reason behind :root not working?
May be worth mention: I used that on my custom component (Angular 5) and I'm using CoreUI (in case that may effect some CSS)
You're talking about Shadow DOM. Elements can get a new kind of node associated with them. This new kind of node is called a shadow root. An element that has a shadow root associated with it is called a shadow host. The content of a shadow host isn’t rendered; the content of the shadow root is rendered instead. There's this thing called Style Encapsulation.
Also I would suggest avoiding the use of :root. I know the docs say to use :root and technically I think that's fine to do at the document level, but you are using a framework maybe there is a conflict inside of the Shadow DOM and cause a bug. Avoiding :root all together might just be a good habit to get into. #pb4now correct me if I'm totally wrong about stuff.
Here's more info about Shadow DOM and read more about Angular Style Components. Hope it helps.

Using react; workflow method for overloading css

I am new to the React javascript framework and have a question about styling using CSS.
Using jQuery, my old workflow was to pick an element on the screen, inspect it in Chrome, note the selector/s that triggered the styling, change the element styling in the browser, and then save it to css/sass etc. If the widget had a hover-state I could make the element visible to see what it looked like.
However using React, and especially for components that someone else has coded, where the component does a 'pop-up' etc, I can't manipulate the DOM to see the component because it is removed from the DOM before I can inspect it.
Now of course I could read the external library code, work out how it works, but CSS inheritance means it would take some time to work out exactly is happening and this seems to be slower than what I was doing before - especially for a simple change.
So my question is, what is the preferred workflow for overloading the CSS for DOM elements that are removed before they can be inspected?

Openlayers style the CSS feature popup

Might anyone know of a way to style the CSS of a popup used in Openlayers?
Using an OL popup method, returned is a div with an ID of
Would I just add that to my CSS and style, or might there be a better way?
Properties:
There are properties such as backgroundColor, border, opacity you can set directly.
Have you taken a look at the popupMatrix example?
JQuery:
In case you use jquery, you can reference the DOM Elements by doing:
popup.contentDiv
popup.groupDiv
popup.closeDiv
Reference
CSS:
Yes, and nothing is stopping you from using css like I demonstrate in this example:
http://jsfiddle.net/BLLqB/1/
Conclusion:
The better way is the one which works best for what you're doing. If you see that the available styling properties are not enough, use jQuery or CSS.

Resources