Path: blob/main/examples/reference/custom_components/JSComponent.ipynb
3240 views
JSComponent simplifies the creation of custom Panel components using JavaScript.
:::{note} JSComponent was introduced in June 2024 as a successor to ReactiveHTML.
JSComponent bears similarities to AnyWidget, but it is specifically optimized for use with Panel.
If you are looking to create custom components using Python and Panel component only, check out Viewer. :::
API
JSComponent Attributes
_esm(str | PurePath): This attribute accepts either a string or a path that points to an ECMAScript module. The ECMAScript module should export arenderfunction which returns the HTML element to display. In a development environment such as a notebook or when using--devflag, the module will automatically reload upon saving changes._importmap(dict | None): This optional dictionary defines an import map, allowing you to customize how module specifiers are resolved._render_policy(Literal['manual', 'children']): Policy that determines when to to re-render (i.e. call the render function) the component. By defaultrender_policy='children', which triggers a full re-render when a child is updated. In'manual'mode updates to children have to be manually handled using.oncallbacks._stylesheets(optional list of strings): This optional attribute accepts a list of CSS strings or paths to CSS files. It supports automatic reloading in development environments.
:::note
You may specify a path to a file as a string instead of a PurePath. The path should be specified relative to the file its specified in.
:::
render Function
The _esm attribute must export the render function. It accepts the following parameters:
model: Represents the Parameters of the component and provides methods to add (and remove) event listeners using.onand.off, render child elements using.get_child, and to.send_eventback to Python.view: The Bokeh view.el: The HTML element that the component will be rendered into.
Any HTML element returned from the render function will be appended to the HTML element (el) of the component but you may also manually append to and manipulate the el directly.
Callbacks
The model.on and model.off methods allow registering event handlers inside the render function. This includes the ability to listen to parameter changes and register lifecycle hooks.
Change Events
The following signatures are valid when listening to change events:
.on('<parameter>', callback): Allows registering an event handler for a single parameter..on(['<parameter>', ...], callback): Allows adding an event handler for multiple parameters at once..on('change:<parameter>', callback): Thechange:prefix allows disambiguating change events from lifecycle hooks should a parameter name and lifecycle hook overlap.
The change: prefix allows disambiguating change events from lifecycle hooks should a parameter name and lifecycle hook overlap.
Bidirectional Events
JS -> Python
.send_event('<name>', DOMEvent): Allows sending browserDOMEventto Python and associating it with a name. An event handler can be registered by name with the.on_eventmethod or by implementing a_handle_<name>method on the class..send_msg(data): Allows sending arbitrary data to Python. An event handler can be registered with the.on_msg(callback)method on the Python component or by implementing a_handle_msgmethod on the class.
Python -> JS
._send_event(ESMEvent, data=msg): Allows sending arbitrary data to the frontend, which can be observed by registering a handler with.on('msg:custom', callback).
Lifecycle Hooks
.on('after_layout', callback): Called whenever the layout around the component is changed..on('after_render', callback): Called once after the component has been fully rendered..on('resize', callback): Called after the component has been resized..on('remove', callback): Called when the component view is being removed from the DOM.
The lifecycle: prefix allows disambiguating lifecycle hooks from change events should a parameter name and lifecycle hook overlap.
Usage
Styling with CSS
Include CSS within the _stylesheets attribute to style the component. The CSS is injected directly into the component's HTML.
Send Events from JavaScript to Python
Events from JavaScript can be sent to Python using the model.send_event method. Define a handler in Python to manage these events. A handler is a method on the form _handle_<name-of-event>(self, event):
You can also define and send arbitrary data using the .send_msg() API and by implementing a _handle_msg method on the component:
Dependency Imports
JavaScript dependencies can be directly imported via URLs, such as those from esm.sh.
Use the _importmap attribute for more concise module references.
See import map for more info about the import map format.
External Files
You can load JavaScript and CSS from files by providing the paths to these files.
Create the file counter_button.py.
Now create the file counter_button.js.
Now create the file counter_button.css.
Serve the app with panel serve counter_button.py --dev.
You can now edit the JavaScript or CSS file, and the changes will be automatically reloaded.
Try changing the
innerHTMLfromcount is ${model.value}toCOUNT IS ${model.value}and observe the update. Note you must updateinnerHTMLin two places.Try changing the background color from
#0072B5to#008080.
Displaying A Single Child
You can display Panel components (Viewables) by defining a Child parameter.
Lets start with the simplest example:
If you provide a non-Viewable child it will automatically be converted to a Viewable by pn.panel:
If you want to allow a certain type of Panel components only you can specify the specific type in the class_ argument.
The class_ argument also supports a tuple of types:
Displaying a List of Children
You can also display a List of Viewable objects using the Children parameter type:
:::note You can change the item_type to a specific subtype of Viewable or a tuple of Viewable subtypes. :::
Render Policy
By default the render_policy='children', which means that when we update the children the component is re-rendered (i.e. the contents are cleared and render is called again). To manually handle child updates you can set `_render_policy='manual' and define a handler that will add the updated children to the DOM:
Now when we update the objects parameter, containing our children, the render_objects handler is called instead of re-creating the entire component from scratch.