Initially, I was hesitant to try ReactiveHTML
but now that I’ve learned it I feel like it’s so powerful–I can build so many custom components easily.
As a simple example, I’ve always wanted a slimmer version of pn.Card
:
TLDR Full Code:
import param
import panel as pn
pn.extension()
class Details(pn.reactive.ReactiveHTML):
title = param.String()
contents = param.Parameter()
_template = """
<details>
<summary>${title}</summary>
${contents}
</details>
"""
details = Details(
title="Hey click me!", contents="Just wanted to show you something cool!"
)
details
Tutorial:
-
I look up how to add collapsible sections in Markdown
-
I paste the gist of it into a ReactiveHTML _template
class Details(pn.reactive.ReactiveHTML):
_template = """
<details>
<summary>Click me</summary>
Contents
</details>
"""
- I replace whatever needs to be changeable with ${parameter_name}:
class Details(pn.reactive.ReactiveHTML):
_template = """
<details>
<summary>${title}</summary>
${contents}
</details>
"""
- I add those parameters to the class.
class Details(pn.reactive.ReactiveHTML):
title = param.String()
contents = param.Parameter()
_template = """
<details>
<summary>${title}</summary>
${contents}
</details>
"""
-
Try it out!
-
And you can update the title/contents dynamically!

4 Likes
Wrapping a div + id around contents allows panel objects to be embedded too:
import param
import panel as pn
pn.extension()
class Details(pn.reactive.ReactiveHTML):
title = param.String()
contents = param.ClassSelector(class_=object)
_template = """
<details>
<summary>${title}</summary>
<div id="inner">${contents}</div>
</details>
"""
details = Details(
title="Hey click me!",
contents="Just wanted to show you something cool!"
)
details
details.contents = pn.indicators.LoadingSpinner()
Unfortunately, this collapses the expanded contents.
Unfortunately can’t add open
dynamically
It’s actually doable with a kwarg; thanks @Marc!
import param
import panel as pn
pn.extension()
class Details(pn.reactive.ReactiveHTML):
title = param.String()
contents = param.ClassSelector(class_=object)
open = param.Boolean()
_template = """
<details id="details" open=${open}>
<summary>${title}</summary>
<div id="inner">${contents}</div>
</details>
"""
details = Details(
title="Hey click me!",
contents="Just wanted to show you something cool!",
open=False
)
pn.Column(
details, details.param.open
).servable()
3 Likes