Chapter 12 — The Reckoning
Every named character converges on the harbour at dawn; two do not walk away, and the map was upside-down the whole time.
This page features interactive demos and side-by-side code samples that need at least 340 pixels of horizontal space. Please widen your browser window, or rotate your device, to continue.
Component <neo-revealable> is a spoiler that obscures children behind an animated grain veil until the user activates it (click, rehide-after ms and whenever the content is patched, important for server-driven UIs so a morph that swaps the secret never flashes it. While concealed the content is inert and aria-hidden, so the secret never leaks to assistive tech and focus can't enter it. Honours prefers-reduced-motion.
The preview routes through the in-browser server simulator. Its current Settings (network latency, a non-200 response, or an unreachable server) are in effect, so the live preview can look like it is misbehaving. Adjust them in the Settings panel.
Every named character converges on the harbour at dawn; two do not walk away, and the map was upside-down the whole time.
The selected state's markup and its scoped CSS. The CSS is wrapped in <style>@scope { ... }</style> and applies to the preview only. Edits change the preview above, applied live while Sync is on, or when you click Patch or Replace. Patch morphs the preview; Replace swaps it outright.
Datastar signals declared in the selected state's markup. Change a value to drive the preview, applied live while Sync is on, or when you click Patch.
| Name | Type | Default | Description |
|---|---|---|---|
open | boolean | false | Set/remove (or use the open JS property / reveal() / conceal() / toggle()) to control it. |
rehide-after | number | 0 | Milliseconds before auto re-conceal after a reveal. 0 or absent keeps it revealed until re-activated. |
variant | "inline" | "media" | none | Obscure treatment. Inferred from the host's height when absent (tall → media, short → inline). |
density | number | 1 | Particle-count multiplier, clamped 0.3–3. |
blur-content | boolean | false | Media variant only: tease the shape with a heavy blur instead of hiding it outright. No effect on text (already hidden — blurring it would just waste a composite). |
| Name | Description |
|---|---|
| default | The content to obscure: text, an image, or a whole subtree. |
| Name | Detail | Bubbles | Description |
|---|---|---|---|
neo-revealable-toggle | { open: boolean } | yes | Fires when the content is revealed or concealed; detail.open is the new state. Conceal also fires from the rehide-after timer and the content-patch auto-hide. |
| Name | Default | Description |
|---|---|---|
--neo-revealable-radius | var(--page-radius, 0.375rem) | Corner radius of the host and cover. |
--neo-revealable-blur | 14px | Blur radius applied to media content while concealed. |
--neo-revealable-veil | color-mix(in srgb, var(--page-fg) 26%, var(--page-bg)) | Frosted cover color. |
--neo-revealable-focus-ring | color-mix(in srgb, var(--accent) 45%, transparent) | Focus outline color. |
--neo-revealable-particle-color | currentColor | Grain color painted onto the cover canvas. |
The default (inline) variant: fine grain in the element's own text colour, sized to the run. Once revealed it stays revealed; set rehide-after to auto-conceal.
One-shot reveal (no auto re-hide):
<p>One-shot reveal (no auto re-hide): <neo-revealable>42</neo-revealable>. Auto re-hide after 2s: <neo-revealable rehide-after="2000">also 42</neo-revealable>.</p>
package examples
import "github.com/romshark/morpheus/neo"
templ RevealableSticky() {
<p>
One-shot reveal (no auto re-hide):{ " " }
@neo.Revealable(neo.RevealableOpts{}) {
42
}
.
Auto re-hide after 2s:{ " " }
@neo.Revealable(neo.RevealableOpts{RehideAfter: neo.Set(2000)}) {
also 42
}
.
</p>
}
variant="media" lays a veil plus sparser particles over a block. Here rehide-after="4000" re-covers it 4s after reveal and after all interactions and focus are gone.
<neo-revealable rehide-after="4000" variant="media">
<img
src="/static/avatar/gh_daniel.jpg"
alt="Boss reveal"
class="revealable-image-img"
>
</neo-revealable>package examples
import (
"github.com/romshark/morpheus/internal/href"
"github.com/romshark/morpheus/neo"
)
templ RevealableImage() {
@neo.RevealableAttrs(neo.RevealableOpts{
Variant: neo.Set(neo.RevealableVariantMedia),
RehideAfter: neo.Set(4000),
}, templ.Attributes{}) {
<img
src={ href.Asset("avatar/gh_daniel.jpg") }
alt="Boss reveal"
class="revealable-image-img"
/>
}
}
.revealable-image-img {
display: block;
width: 16rem;
height: auto;
}
blur-content keeps the image visible but heavily blurred, so the composition teases without giving the subject away, a softer mode than the fully-veiled image above.
<neo-revealable variant="media" blur-content>
<img
src="/static/avatar/gh_roman.jpg"
alt="Spoiler portrait"
class="revealable-blur-image-img"
>
</neo-revealable>package examples
import (
"github.com/romshark/morpheus/internal/href"
"github.com/romshark/morpheus/neo"
)
templ RevealableBlurImage() {
@neo.RevealableAttrs(neo.RevealableOpts{
Variant: neo.Set(neo.RevealableVariantMedia),
BlurContent: neo.Set(true),
}, templ.Attributes{}) {
<img
src={ href.Asset("avatar/gh_roman.jpg") }
alt="Spoiler portrait"
class="revealable-blur-image-img"
/>
}
}
.revealable-blur-image-img {
display: block;
width: 16rem;
height: auto;
}
Any subtree works. blur-content also blurs the hidden block, so the shape teases without giving the text away.
Every named character converges on the harbour at dawn; two do not walk away, and the map was upside-down the whole time.
<neo-revealable variant="media" blur-content class="revealable-section-host">
<article class="revealable-section-body">
<h4 class="revealable-section-title">Chapter 12: The Reckoning</h4>
<p class="revealable-section-text">Every named character converges on the harbour at dawn; two do not walk away, and the map was upside-down the whole time.</p>
</article>
</neo-revealable>package examples
import "github.com/romshark/morpheus/neo"
templ RevealableSection() {
@neo.RevealableAttrs(neo.RevealableOpts{
Variant: neo.Set(neo.RevealableVariantMedia),
BlurContent: neo.Set(true),
}, templ.Attributes{"class": "revealable-section-host"}) {
<article class="revealable-section-body">
<h4 class="revealable-section-title">Chapter 12: The Reckoning</h4>
<p class="revealable-section-text">
Every named character converges on the
harbour at dawn; two do not walk away,
and the map was upside-down the whole
time.
</p>
</article>
}
}
.revealable-section-host {
max-width: 30rem;
}
.revealable-section-body {
padding: 1rem;
}
.revealable-section-title {
margin: 0 0 0.5rem;
}
.revealable-section-text {
margin: 0;
}
Cover and grain are CSS custom properties, not attributes. Override --neo-revealable-veil (panel background) and --neo-revealable-particle-color (grain) per instance via inline style, or theme-wide.
Rendezvous at pier 9, 02:00. The asset answers to "Wren".
<neo-revealable variant="media" class="revealable-styled-host">
<article class="revealable-styled-body">
<h4 class="revealable-styled-title">Classified: Operation Nightjar</h4>
<p class="revealable-styled-text">Rendezvous at pier 9, 02:00. The asset answers to "Wren".</p>
</article>
</neo-revealable>package examples
import "github.com/romshark/morpheus/neo"
templ RevealableStyled() {
@neo.RevealableAttrs(neo.RevealableOpts{
Variant: neo.Set(neo.RevealableVariantMedia),
}, templ.Attributes{
"class": "revealable-styled-host",
}) {
<article class="revealable-styled-body">
<h4 class="revealable-styled-title">Classified: Operation Nightjar</h4>
<p class="revealable-styled-text">
Rendezvous at pier 9, 02:00. The asset
answers to "Wren".
</p>
</article>
}
}
.revealable-styled-host {
--neo-revealable-veil: #1e1b4b;
--neo-revealable-particle-color: #67e8f9;
}
.revealable-styled-body {
padding: 1rem;
max-width: 28rem;
}
.revealable-styled-title {
margin: 0 0 0.5rem;
}
.revealable-styled-text {
margin: 0;
}