Advanced Components


Work in progress. The example works but requires much more elucidation


In most cases, components can be defined using Python only as previously described in this tutorial. In some cases however, in parallel to the Python definition, a Vue.js component also needs to be created.

In this chapter, we will create a signing pad component based on signature_pad


If you are not familiar with Vue.js, this chapter will not be very useful to you.

The Components Directory

Under your applications static directory (the default is the directory the application is run form) create another directory called components. Put the your JavaScript component definition there. Files must all have the extension .js.

The application will load these files automatically.


import justpy as jp

class SignaturePad(jp.JustpyBaseComponent):

    vue_type = 'signaturepad'

    def __init__(self, **kwargs):

        self.options = jp.Dict()
        self.classes = '' = ''
        self.width = 400
        self.height = 200
        self.clear = False = True
        self.event_propagation = True
        self.pages = {}
        kwargs['temp'] = False  # Force an id to be assigned to pad
        self.allowed_events = ['onEnd', 'onBegin']
        if type(self.options) != jp.Dict:
            self.options = jp.Dict(self.options)

    def add_to_page(self, wp: jp.WebPage):

    def react(self, data):

    def convert_object_to_dict(self):
        d = {}
        d['vue_type'] = self.vue_type
        d['id'] =
        d['show'] =
        d['classes'] = self.classes
        d['style'] =
        d['event_propagation'] = self.event_propagation
        d['def'] = self.options
        d['events'] =
        d['width'] = self.width
        d['height'] = self.height
        d['clear'] = self.clear
        d['options'] = self.options
        return d

def my_end(self, msg):
    print(msg) =

async def clear_pad(self, msg):
    self.pad.clear = True
    self.pad.clear = False
    return True

def pad_test():
    wp = jp.WebPage()
    wp.head_html = '<script src=""></script>'
    pad = SignaturePad(a=wp, style = 'background-color: white; border: 1px solid;', classes='m-2', onEnd=my_end)
    pad.options = {'penColor': 'blue'}
    clear_btn = jp.Button(text='Clear Pad', classes=jp.Styles.button_simple + ' m-2', a=wp, click=clear_pad)
    clear_btn.pad = pad
    return wp


Vue.js Component

var signature_pads = {};
    Vue.component('signaturepad', {
            `<canvas  v-bind:id="" :class="jp_props.classes"  :style="" :width="jp_props.width" height="jp_props.height"></canvas>`,
        methods: {
            pad_change() {
                var id = this.$;
                var canvas = document.getElementById(id);
                var signaturePad = new SignaturePad(canvas, this.$props.jp_props.options);
                signature_pads[id] = signaturePad;
                var events = this.$;
                var props = this.$props;

                function onEnd() {
                    if (events.includes('onEnd')) {
                        var data = signaturePad.toDataURL('image/png');
                        var point_data = signaturePad.toData();
                        var e = {
                            'event_type': 'onEnd',
                            'class_name': props.jp_props.class_name,
                            'html_tag': props.jp_props.html_tag,
                            'vue_type': props.jp_props.vue_type,
                            'page_id': page_id,
                            'websocket_id': websocket_id,
                            'data': data,
                            'point_data': point_data
                        send_to_server(e, 'event');

                signaturePad.onEnd = onEnd;

        mounted() {
        updated() {

            if (this.$props.jp_props.clear) {
        props: {
            jp_props: Object