Developing custom models
Panel ships with a number of custom Bokeh models, which have both Python and Javascript components. When developing Panel these custom models have to be compiled. This happens automatically with pip install -e . or pixi run install, however when running actively developing you can rebuild the extension with panel build panel from the source directory. The build command is just an alias for bokeh build; see the Bokeh developer guide for more information about developing bokeh models.
Just like any other Javascript (or Typescript) library Panel defines a package.json and package-lock.json files. When adding, updating or removing a dependency in the package.json file ensure you commit the changes to the package-lock.json after running npm install.
Adding a new Custom Model
This example will guide you through adding a new model.
We will use the the ChartJS model as an example. But you should replace ChartJS and similar with the name of your model.
Here we will add a simple Button model to start with. But we call it ChartJS.
My experience is that you should start small with a working example and the continue in small, incremental steps. For me it did not work trying to copy a large, complex example and refactoring it when I started out learning about Custom Models.
Create a new branch
chartjs.Add the files and code for a minimum working model. This includes
A Panel Python model
A Bokeh Python and TypeScript model
Add the Panel Python Model
Add the file panel/pane/chartjs.py and the code
Add the Panel model to panel/pane/__init__.py
Add the Bokeh Python Model
Add the file panel/models/chartjs.py and the code
Add the Bokeh model to panel/models/__init__.py file
Add the Bokeh TypeScript Model
Add the file panel/models/chartjs.ts and the code
Add the ChartJS typescript model to panel/models/index.ts
Build the Model
You can now build the model using panel build panel. It should look similar to
Test the Model
Add the file panel/tests/pane/test_chartjs.py and the code
Run pytest panel/tests/pane/test_chartjs.py and make sure it passes.
Serve the app with panel serve panel/tests/pane/test_chartjs.py --auto --show
You have to hard refresh your browser to reload the new panel .js files with your ChartJS model. In Chrome I press CTRL+F5. See How to hard refresh in Chrome, Firefox and IE for other browsers.
Now you can manually test your model

Save your new Model
Finally you should save your changes via git add . and maybe even commit them git commit -m "First iteration on ChartJS model"
Build a small HTML Example
In the beginning of your journey into Custom Models there will be things that break and difficulties figuring out why. When you combine several new things it can be really difficult to figure out why. Is the problem Panel, Bokeh, Python, Javascript, Node or ....?
So I suggest creating a small, working example in plain HTML/ JS before you start combining with Panel and Bokeh Models.
Please note the below example works out of the box. It is not always that easy importing javascript libraries in a Notebook. So it can be a good idea to work in a .html file first.
Using the Javascript Model
Getting something shown using the ChartJS js library would be the next step. It might require a bit of experimentation, looking at other examples, google or support from the community.
Here I found that a good step where the following changes
Import the Javascript Library
Update test_chartjs.py tp
Render the Plot
In the chartjs.ts file add import { canvas, div } from "@bokehjs/core/dom"; at the top and change the render function to
Build and Test
Run panel build panel and hard refresh your browser. You should see

Save Your Model
Remember to stage and/ or commit your working changes.
Next Steps
Enable setting the Python
ChartJS.objectparameter to any ChartJS dictionary.Checkout support for different sizing modes, responsiveness and window maximize.
Configure the javascript, css, .. dependencies in the Bokeh Python File.
.....
Check List
When you develop and test your model eventually you should consider implementing and testing
Dynamic updates to the
objectparameter and any other parameters added.Resizing
Does it resize when
widthis changed dynamically?Does it resize when
heightis changed dynamically?Does it work with
sizing_mode="stretch_width"etc.
Themes (Light, Dark)
Window Resizing, Window Maximizing, Window Minimizing.
Streaming of Data. Is it efficient?
Events (Click, Hover etc.)
Consider supporting the Python Wrapper (ECharts -> PyECharts, ChartJS -> PyChart.JS)
Tests
Reference Notebook
Communication also to for example ChartJS community and developers.
Tips and Tricks
Work in small increments and stage your changes when they work
Remember to
panel build paneland hard refresh before you test.Add console.log statements to your
.tscode for debugging.Use the Developer Tools console to see the
console.logoutput and identify errors. In my browsers I toggle the Developer Tools usingCTRL+SHIFT+I.Find inspiration for next steps in the existing Panel Custom Models. For
ChartJSone of the most relevant custom models would beEcharts. See Panel echarts.py, Bokeh echarts.py and echarts.ts.Use the existing documentation
Use Google Search. You don't have to be an expert javascript or typescript developer. It's a very small subset of those languages that is used when developing Custom Models.
Ask for help in Discord, HoloViz Discourse and Bokeh Discourse forums.
Bundling resources
Panel bundles external resources required for custom models and templates into the panel/dist directory. The bundled resources have to be collected whenever they change, so rerun pip install -e . or pixi run install, whenever you change one of the following:
A new model is added with a
__javascript_raw__declaration or an existing model is updatedA new template with a
_resourcesdeclaration is added or an existing template is updatedA CSS file in one of template directories (
panel/template/*/) is added or modified