Wrapping Material UI components#

Note

The MaterialBase component is defined before the call to pn.extension to allow us to load the _extension_name and thereby initialize the required JS and CSS resources. Ordinarily the component would be defined in an external module.

import param
import panel as pn

from panel.reactive import ReactiveHTML

class MaterialBase(ReactiveHTML):

    __javascript__ = ['https://unpkg.com/material-components-web@latest/dist/material-components-web.min.js']

    __css__ = ['https://unpkg.com/material-components-web@latest/dist/material-components-web.min.css']

    _extension_name = 'material_ui'

pn.extension('material_ui', template='material')

This example demonstrates how to wrap Material UI components using ReactiveHTML.

class MaterialTextField(MaterialBase):

    value = param.String(default='')

    _template = """
    <label id="text-field" class="mdc-text-field mdc-text-field--filled">
      <span class="mdc-text-field__ripple"></span>
      <span class="mdc-floating-label">Label</span>
      <input id="text-input" type="text" class="mdc-text-field__input" aria-labelledby="my-label" value="${value}"></input>
      <span class="mdc-line-ripple"></span>
    </label>
    """

    _dom_events = {'text-input': ['change']}

    _scripts = {
        'render': "mdc.textField.MDCTextField.attachTo(text_field);"
    }

class MaterialSlider(MaterialBase):

    end = param.Number(default=100)

    start = param.Number(default=0)

    value = param.Number(default=50)

    _template = """
    <div id="mdc-slider" class="mdc-slider" style="width: ${model.width}px">
      <input id="slider-input" class="mdc-slider__input" min="${start}" max="${end}" value="${value}">
      </input>
      <div class="mdc-slider__track">
        <div class="mdc-slider__track--inactive"></div>
        <div class="mdc-slider__track--active">
          <div class="mdc-slider__track--active_fill"></div>
        </div>
      </div>
      <div class="mdc-slider__thumb">
        <div class="mdc-slider__thumb-knob"></div>
      </div>
    </div>
    """

    _scripts = {
        'render': """
            slider_input.setAttribute('value', data.value)
            state.slider = mdc.slider.MDCSlider.attachTo(mdc_slider)
        """,
        'value': """
            state.slider.setValue(data.value)
        """
    }

slider     = MaterialSlider(value=5, start=0, end=100, width=200)
text_field = MaterialTextField()

pn.Row(
    pn.Column(
        slider.controls(['value']),
        slider
    ),
    pn.Column(
        text_field.controls(['value']),
        text_field
    ),
).servable()