Panel 1.3.0 Release

Release announcement for Panel 1.3

Philipp Rudiger


October 24, 2023

What is Panel?

Panel is an open-source Python library that lets you easily build powerful tools, dashboards and complex applications entirely in Python. It has a batteries-included philosophy, putting the PyData ecosystem, powerful data tables and much more at your fingertips. High-level reactive APIs and lower-level callback based APIs ensure you can quickly build exploratory applications, but you aren’t limited if you build complex, multi-page apps with rich interactivity. Panel is a member of the HoloViz ecosystem, your gateway into a connected ecosystem of data exploration tools.

New release!

We are very pleased to announce the 1.3.0 release of Panel! This release packs many exciting new features, specifically:

Special thanks to our first time contributors @aktech, @meson800 and @monodera and returning contributors @cdeil, @pierrotsmnrd and @TheoMartin. We also want to highlight the contribution of our new core contributor @ahuang11 for developing the chat components and recognize @MarcSkovMadsen and @philippjfr for their efforts on testing and improving these new components. Finally we thank the entire core team including @sophiamyang, @Hoxbro, @MarcSkovMadsen, @maximlt, @ahuang11 and @philippjfr for their continued efforts.

If you are using Anaconda, you can get latest Panel with conda install panel , and using pip you can install it with pip install panel.

Chat Components

With the huge amount of popularity of LLMs it is way overdue for Panel to add components that make it easy to interact with them. See the following trailer as a quick introduction:

and find a variety of examples demonstrating the cabilities of these new features at Panel Chat Examples page, including examples using LangChain, OpenAI, Mistral, Llama, and RAG.

In Panel we want to focus on building general components that let you achieve what you need but also provide the flexibility to compose components as needed. Therefore the subpackage consists of a number of components which are composable incudling the:

These components build on each other as shown in the diagram below:

At the core is a ChatMessage which can encapsulate any other output and associates this with a user, a timestamp and reaction icons:

msg ='When did Panel add support for Chat components?', user='User')


The ChatFeed adds support for composing multiple ChatMessages and a simply API for sending new messages:

feed =

feed.send('Chat components were added in v1.3.0!', user='Developer', avatar='👩')


Lastly the ChatInterface extends the ChatFeed by adding a UI for interacting with the ChatFeed:*feed, width=600)

Finally we have added basic support for integrating with LangChain via the PanelCallbackHandler, which we hope will eventually be merged into Langchain itself (if you’re a Langchain dev, call us 😊).

Reactive Expressions & References

Panel 1.3.0 now requires Param 2.0 which we are releasing simultaneously. Not only does the new Param release clean up the namespace of all Panel objects but it also adds support for two major new capabilities:

  • Allow passing parameters, widgets, expressions and bound functions as references to Panel components
  • Integrating support for reactive expressions using the param.rx API

To unpack this a little bit let’s play around with rx a little bit:

slider = pn.widgets.IntSlider(start=0, end=7, value=3)

slider.rx() ** 2

This very simple example demonstrates the core idea behind reactive expressions. It allows you to treat a dynamic reference, e.g. a widget value, as if it was the actual object, in this case an int. This allows you to build reactive pipelines using natural syntax. To discover more about reactive expressions, see the Param documentation.

Of course this extends well beyond this simple example and when combined with the ability for Panel components to resolve references makes it possible to write complex interactive components using natural syntax:

dataset = pn.widgets.Select(name='Pick a dataset', options={
    'penguins': '',
    'stocks': ''
nrows = pn.widgets.IntSlider(value=5, start=0, end=20, name='N rows')

# Load the currently selected dataset and sample nrows from it
df = pn.bind(pd.read_csv, dataset).rx().sample(n=nrows)

# Bind the current value of the `df` expression to the Tabulator widget
table = pn.widgets.Tabulator(df, page_size=5, pagination='remote')

pn.Row(pn.Column(dataset, nrows), table)

Using pn.bind we can dynamically load various datasets and then apply transformations by turning the result into a reactive expression, e.g. to sample a variable number of rows from the dataset. Lastly we can pass the resulting reactive expression to Tabulator which will automatically reflect the result of the expression.

Not only can Panel now resolve such expressions but it can even resolve references nested inside another object:

font_size = pn.widgets.FloatSlider(start=6, end=24, value=12, name='Font Size')
color = pn.widgets.ColorPicker(name='Color')

    pn.Column(font_size, color),
    pn.pane.HTML('Hello World!', styles={'color': color, 'font-size': pn.rx('{}pt').format(font_size)})

Enhancements & Components

OAuth improvements

Panel has shipped with OAuth integration for a very long time. In this release we finally spent some time rationalizing the code and adding support for:

  • Authorization code and password based OAuth grant workflows for when you don’t want to issue a client secret for your Panel application
  • Adding the ability to automatically refresh access_tokens whenever they expire using the --oauth-refresh-tokens (discover more here)

Authorization callbacks

If you are using OAuth or basic authentication with Panel you can now provide an authorization_callback that does not only allow you to either allow or deny a user access to a particular app but now also allows you to redirect them elsewhere. Discover more here.

Colormap Widget

The new ColorMap widget makes it easy to let users pick between multiple color palettes.

from import Reds, Greens, Blues, viridis

cmaps = {'Reds': Reds, 'Greens': Greens, 'Blues': Blues, 'viridis': viridis}

pn.widgets.ColorMap(options=cmaps, ncols=2)



  • Integrate support for param reactive expressions and expose pn.rx (#5138, #5582)
  • Implement ChatMessage, ChatFeed and ChatInterface components (#5333)
  • Unify OAuth implementations and refresh access_token (#5627)
  • Add ColorMap widget (#5647)


  • Add unit to widget in HoloViews pane if provided (#5535)
  • Allow registering global on_session_destroyed callback (#5585)
  • Implement auto_grow on TextAreaInput (#5592)
  • Add ability to redirect users from authorization callback (#5594)
  • Add support for Path object in FileDownload (#5607)
  • Add authorization_code and password based OAuth login handlers (#5547)
  • Add format to EditableFloatSlider and EditableIntSlider (#5631)
  • Add support for decorating async functions with (#5649)
  • Map param.Bytes to FileInput widget (#5665)

Bug fixes

  • Fixes for Column invisible scroll_button taking space (#5532)
  • Guard undefined values from being set on BrowserInfo (#5588)
  • Fix thumbnails and use Panel design on index page (#5595)
  • Fix regressions in TextEditor caused by migration to shadow DOM (#5609)
  • Sync location state from request (#5581)
  • Fix Select widget label offset in Material Design (#5639)
  • Override token contents when reusing sessions (#5640)
  • Fix patching a table with a DataFrame with a custom index (#5645)
  • Set FloatPanel status correctly on initialization (#5651)
  • Fix patching table with pd.Timestamp values (#5650)
  • Ensure notifications and browser_info are loaded when HoloViews is loaded
  • Gracefully handle resolution of invalid paths in _stylesheets (#5666)
  • Handle patching tables with NaT values (#5675)


  • Upgrade to Param 2.0
  • Compatibility with Bokeh 3.3.0


  • Improved docs on deploying with GCP (#5531)
  • Add Streamlit migration guide for chat components (#5670)
Back to top