DEV Community

Cover image for Dynamic styling of Shadow Host - craftkit code pattern
CraftkitJS
CraftkitJS

Posted on • Edited on

Dynamic styling of Shadow Host - craftkit code pattern

Usually, it is enough to define style only for the .root and its children. But sometimes, you want to edit style for host element. Here is patterns for this.

Define Shadow Host style

To define Shadow Host style, just write CSS in :host as usual.

class Example extends Craft.UI.View {
    style(componentId){
        return `
            :host {
                padding-top: env(safe-area-inset-top);
                padding-left: env(safe-area-inset-left);
                padding-right: env(safe-area-inset-right);
            }
        `;
    }
}
Enter fullscreen mode Exit fullscreen mode

Direct Host style modification

You can directly update Host element styling via this.shadow.host.style[*].

class Example extends Craft.UI.View {
    updateShadowHostWidth(){
        this.shadow.host.style.width = '200px';
    }
    style(componentId){
        return `
            :host {
                width: 100px;
            }
        `;
    }
}
Enter fullscreen mode Exit fullscreen mode

Swap Shadow Host CSS class

If you would like to change style of Host element on the fly, your target class should be defined in the parent component to be able to affect the shadow element.

class Example extends Craft.UI.View {
    viewDidLoad(callback){
        this.appendView(new ExampleCore());
        if(callback){ callback(); }
    }
    style(componentId){
        return `
            .light { color:#333; background-color: #fff; }
            .dark { color:#fff; background-color: #333; }
        `;
    }
}

class ExampleWrapped extends Craft.UI.View {
    constructor(options){
        super(options);
        this.data = { mode:0 };
    }
    toggleMode(){
        if( this.data.mode++ % 2 ){
            this.shadow.host.classList.add('light')
            this.shadow.host.classList.remove('dark')
        }else{
            this.shadow.host.classList.add('dark');
            this.shadow.host.classList.remove('light')
        }
    }
    style(componentId){
        return `
            :host { color:#333; background-color: #fff; }
            .root { 
                width:100px; marign-left:auto; marign-right:auto;
            }
        `;
    }
    template(componentId){
        return `
            <div id="root" class="root" 
            onclick="${componentId}.toggleMode()">
                Hello!
            </div>
        `;
    }
}
Enter fullscreen mode Exit fullscreen mode

Discouraged pattern

You can write something like the following code, but the code goes back and forth. So, this pattern should be avoided.

class ExampleWrapper extends Craft.UI.View {
    constructor(options){
        super(options);
        this.data = { mode:1 };
        this.views = { example:null };
    }
    viewDidLoad(callback){
        this.views.example = new ExampleWrapped({delegate:this});
        this.appendView(this.views.example);
        if(callback){ callback(); }
    }
    toggleMode(){
        if( this.data.mode++ % 2 ){
            this.views.example.darkMode();
        }else{
            this.views.example.lightMode();
        }
    }
    style(componentId){
        return `
            .light { color:#333; background-color: #fff; }
            .dark { color:#fff; background-color: #333; }
        `;
    }
}

class ExampleWrapped extends Craft.UI.View {
    constructor(options){
        super(options);
        this.delegate = options.delegate;
    }
    lightMode(){
        this.shadow.host.classList.add('light')
        this.shadow.host.classList.remove('dark')
    }
    darkMode(){
        this.shadow.host.classList.add('dark');
        this.shadow.host.classList.remove('light')
    }
    style(componentId){
        return `
            :host { color:#333; background-color: #fff; }
            .root { 
                width:100px; marign-left:auto; marign-right:auto;
            }
        `;
    }
    template(componentId){
        return `
            <div id="root" class="root" 
            onclick="${componentId}.delegate.toggleMode()">
                Hello!
            </div>
        `;
    }
}
Enter fullscreen mode Exit fullscreen mode

NOTE

Above examples are runnable on playground.

var view = new Example();
view.loadView();
Craft.Core.Context.getRootViewController().appendSubView(view);
Enter fullscreen mode Exit fullscreen mode

🛺 Try CraftKit Playground:
https://github.com/craftkit/craftkit-playground

Top comments (0)