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
opened 06:51PM - 08 Aug 23 UTC
TRIAGE
I want to do something like ` {% if collapsed %} {% else %} open {% endif %}` dy… namically.
The following works initially
```python
import param
import panel as pn
pn.extension()
class Details(pn.reactive.ReactiveHTML):
title = param.String()
contents = param.ClassSelector(class_=object)
collapsed = param.Boolean(default=False)
_template = """
<details {% if collapsed %} {% else %} open {% endif %}>
<summary>${title}</summary>
<div id="inner">${contents}</div>
</details>
"""
details = Details(
title="Hey click me!",
contents="Just wanted to show you something cool!",
collapsed=False
)
details.show()
```
However it's not dynamic, i.e. I can't set `details.collapsed = True` so I try:
```python
import param
import panel as pn
pn.extension()
class Details(pn.reactive.ReactiveHTML):
title = param.String()
contents = param.ClassSelector(class_=object)
open = param.ObjectSelector(default="open", objects=["open", ""])
_template = """
<details id="details" ${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="open"
)
details.show()
```
But I think because `open` is not a key/value pair, it doesn't work.
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
Nice blog post! More of these please!
One suggestion in case you are interested: Explain a bit more in detail what is we are seeing in each example gif. It may not be obvious to someone that does not already know what to expect.
1 Like