Search code examples
custom-elementsveltesvelte-component

(an alternative for) Creating dynamic CSS in a STYLE element per Svelte component


I am learning Svelte by converting my existing (proof concept) Chess Custom Element/WebComponent.

One objective is to highlight the squares a dragging Chesspiece can move to

In my Custom Element it is fairly easy with a Stylesheet (inside Board shadowDOM !!! )

<style id="moveFromSquare"></style>

Then a mousenter on a square creates the CSS with the correct squarename
(for screenshot: local variables at='D5' and piece='black-knight')

let squareMouseEnter = () => {
    [boardcustomelement].root.querySelector('moveFromSquare').innerHTML=
    piece
      ? `div[at=  "{at}"  ]{
            box-shadow: inset 0 0 var(--boxshadow-size) var(--boxshadow-color);
         }
         div[defenders*=  "{at}"  ]{
            font-weight:bold;
            color:green;
            box-shadow: inset 0 0 var(--boxshadow-size) var(--boxshadow-color);
        }`
      : ''
}

No need for looping over previous squares to clean classnames,
No need for looping over squares again to set classnames

But I am learning Svelte...

Everything is a Svelte object: Board, Square, Piece (inside Square)

There can be multiple Boards on a page,
since there is no shadowDOM, to apply my CSS approach:

  • I need to get the svelte-xxxxx className for one Board (what is the easier way?)
  • then create a (global) <STYLE> element for every board using the svelte-xxxxx className everywere required

But I wonder if there is a more (reactive) Svelte way of creating this?


Solution

  • What I got (for now) is creating the dynamic CSS in a (Svelte) DIV (Childnode of the Board) than transferring it to the Components STYLE element:

    <script>
        import {afterUpdate} from 'svelte';
        let DynamicStyleDIV;
        let parentClass;
        let square='D3';//todo handle dynamic update
        let CSS = x => `{${x}}`;
    
        afterUpdate(()=>{
            parentClass = DynamicStyleDIV.parentNode.className;
            let selector = DynamicStyleDIV.className+'-style';
            setTimeout(() => document.getElementById(selector).innerHTML = DynamicStyleDIV.innerHTML);
        })
    </script>
    
    
    <div bind:this={DynamicStyleDIV} hidden>
        .{parentClass} div[at="{square}"][at="{square}"]{CSS('background:gold')}
    </div>
    
    
    <style>
        div{/*required because an empty style element is ignored*/}
    </style>
    

    But this only works in the Svelte REPL

    Where styles are <style> elements in the document, and not rules in bundle.css