Customize panel components/widgets design

Hello,
I was wondering if it would be possible to customize panel widgets design.
For example, I am not really crazy about the Select widgets (screenshot below)
Screenshot 2022-08-30 at 10.51.28
Screenshot 2022-08-30 at 10.51.36

I have already tried to modify the CSS, but the modifications are limited.

Same question for the loading spinner is it possible to use a custom one ?

1 Like

Hi @hadmaria

You can get other widgets in different ways.

1 Like

Here is an example custom select

from panel.reactive import ReactiveHTML
import param

# See https://shoelace.style/components/select
class ShoelaceSelect(ReactiveHTML):
    min_height= param.Integer(70)
    min_width= param.Integer(300)
    value = param.Parameter()
    options = param.List()
    
    def __init__(self, **params):
        super().__init__(**params)

        if self.options and not self.value:
            self.value = self.options[0]
    
    _template = """
<div id="pn-container" style="height:100%;width:100%">
    <sl-select id="select" label="${name}" value="${value}">
    {% for option in options %}
        <sl-menu-item id="option-{{ loop.index0 }}" value="{{ option }}">{{ option }}</sl-menu-item>
    {% endfor %}
    </sl-select>
</div>
"""

    __javascript_modules__=["https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.0.0-beta.82/dist/shoelace.js"]
    __css__ = ["https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.0.0-beta.82/dist/themes/light.css"]
    
    _scripts = {
        "render": """
select.addEventListener('sl-select', event => {
    data.value = event.detail.item.value
});
"""
    }

import panel as pn

pn.extension()

select = ShoelaceSelect(options=["apple", "pear", "banana"], name="Fruit")

pn.Column(select, select.param.value).servable()
1 Like

Thank you very much, this is exactly what I was looking for.

Do you know how to use, for example, the ShoelaceSelect as a panel widgets ?

More precisely, is it possible to inherit the ShoelaceSelect from the panel.widgets.Select object while keeping its customised design and hence to be able to have a watcher over a param variable which stored the value of the ShoelaceSelect widget ?

1 Like

Hi @hadmaria

The ShoelaceSelect widget above works just as the normal Select because it also has the value and options parameter. So you can depend, bind etc. on select.param.value as you would normally do.

import panel as pn

pn.extension()

select = ShoelaceSelect(options=["apple", "pear", "banana"], name="Fruit")

def to_string(value):
    return f"The value is {value}"

ito_string = pn.bind(to_string, value=select.param.value)

pn.Column(select, select.param.value, pn.panel(ito_string, width=300)).servable()

3 Likes