Reveal
A lid that slides aside to expose a belly of detail or actions underneath.
Live demo
Reveal layers a lid over as many as four bellies, one per direction, and slides the lid to expose whichever the gesture asks for. Which directions are live is inferred from the bellies you fill: a [slot="end"] makes the end direction live and nothing else does, so there is no second list of directions to keep in sync.
Travel is locked to one axis per gesture, so a component offering start and bottom still only ever moves one way at a time. Every knob is a host attribute, so the same markup configures identically from HTML, Svelte, and Astro; behavior sets the default and endBehavior and friends override one direction. Each direction decides what its own slide means: latch opens and stays, commit fires an action and springs back, and both gives the short pull a latch and the full pull the action. Give several reveals a shared name and they behave like radios, where opening one closes the last; leave the name off and they behave like checkboxes, each independent. A concealed belly is inert, so its buttons never sit in the tab order waiting to be tabbed into by accident.
When to use
How this component composes with the rest of the set.
Props
46 props, straight from the manifest.
| Prop | Type | Default | Bindings | Description |
|---|---|---|---|---|
<xtyle-reveal-group>, falling back to the document, so two unrelated lists can reuse a name without cross-talk. | ||||
latch opens and stays open, commit fires the belly's action and springs back, and both gives a short pull the latch and a full pull the action. | ||||
parallelogram, chevron, ticket, heart) or any clip-path value outright, so a caller can hand over a shape the library has never heard of: shape="polygon(0 0, 100% 20%, 100% 100%, 0 80%)". Register more names with registerRevealShapes(), last-wins on the name, the way the effect library takes verbs. Percentages scale with the box; absolute units do not. Set contained to hold the sliding lid inside the box's bounds instead of letting it travel clear. | ||||
<svg>, a photo) the picture should run to the edge; for a lid carrying text it should not, which is why the inset is the default. It drops the inset and nothing else: sizing the artwork stays the author's, since forcing a height onto content with its own aspect ratio blows the box open. | ||||
role="button" in place of role="group". A reveal whose lid carries a picture and a name, and whose pull is the only way to act, is a button by every test a screen reader applies. Opt-in, because the lid takes whatever you slot into it and a lid holding its own buttons is genuinely a container. Pair it with label. | ||||
shape; an unshaped box always contains its lid. | ||||
--{tone}-bg, its text from --{tone}-text, and a frame from --{tone}), so a belly reads as accept or decline at a glance. Any tone in the roster works: the semantic roles, the accent-ramp variants, and the named hues. | ||||
1 lets it come clear, and a smaller value suits a row that only needs to show an action. Overridable per direction. | ||||
glyph is the roster icon, which says what the edge does; bar and dots are quiet marks for a lid carrying artwork, where an icon reads as clutter; none draws no grip at all, leaving the drag and the arrow keys as the way in. Overridable per direction. | ||||
gripSize sets the grip's hit area. | ||||
0.4) or a percentage (40%). A belly can override it for its own direction. | ||||
commit or both belly. Same fraction-or-percentage shape as latchAt, and overridable per belly. | ||||
tone for the start belly alone, which is how one box declines in red and accepts in green. | ||||
xtyle.icons slot. | ||||
tone for the end belly alone, which is how one box declines in red and accepts in green. | ||||
xtyle.icons slot. | ||||
tone for the top belly alone, which is how one box declines in red and accepts in green. | ||||
xtyle.icons slot. | ||||
tone for the bottom belly alone, which is how one box declines in red and accepts in green. | ||||
xtyle.icons slot. | ||||
travel for the start direction alone. | ||||
travel for the end direction alone. | ||||
travel for the top direction alone. | ||||
travel for the bottom direction alone. | ||||
gripStyle for the start direction alone. | ||||
gripStyle for the end direction alone. | ||||
gripStyle for the top direction alone. | ||||
gripStyle for the bottom direction alone. | ||||
behavior for the start direction alone. | ||||
latchAt for the start direction alone. | ||||
commitAt for the start direction alone. | ||||
behavior for the end direction alone. | ||||
latchAt for the end direction alone. | ||||
commitAt for the end direction alone. | ||||
behavior for the top direction alone. | ||||
latchAt for the top direction alone. | ||||
commitAt for the top direction alone. | ||||
behavior for the bottom direction alone. | ||||
latchAt for the bottom direction alone. | ||||
commitAt for the bottom direction alone. |
Events
What the component emits, and what rides along on event.detail. The name in the
first column is the one addEventListener takes.
| Event | Detail | Bindings | Description |
|---|---|---|---|
Enter or Space on the lid, or commit(direction). |
Methods
What you can call on the element itself — the half of the surface a prop or an event cannot express. A control driven by a gesture, or one whose state the platform owns, opens here. Astro renders on the server and hands back no instance, so no method is reachable from it.
| Method | Returns | Bindings | Description |
|---|---|---|---|
latchAt does. Ignored for a direction with no belly, and on a disabled reveal. | |||
commitAt does. This is the door for a test harness: a reveal's only other input is an analogue gesture, and driving one from a script means reproducing axis lock, travel fractions, and pointer capture rather than saying what you mean. A latch direction has no action to take, so this opens it instead, and closes it if it is already open. |
Appearance
States
open
A belly is exposed; the modifier names which direction.
grouped
The reveal carries a name, so opening it closes its peers.
disabled
The lid is locked and the bellies are hidden.
Anatomy
The named parts that make up the component. A ::part() handle is reachable from your own stylesheet; the class beside it is the component's internal selector, which a shadow boundary keeps to itself.
lid
The lid: the sliding surface holding the default slot's content. Focusable, and the target of the drag.
belly
What sits under the lid in one direction, revealed as the lid slides off it.
grip
The edge affordance for a direction, giving a pointer-free way to open that belly.
Tokens & coverage
What the component consumes, checked live against what the algorithm produces.
Live coverage check against the xtyle-default register
(derive(xtyleDefault, { anchors }) →
coverComponent(manifest, register)). Every token this component
consumes must be a key the algorithm produces.
--accent--accent-2--accent-2-bg--accent-2-text--accent-3--accent-3-bg--accent-3-text--accent-4--accent-4-bg--accent-4-text--accent-bg--accent-text--bg-1--bg-2--black--black-bg--black-text--blue--blue-bg--blue-text--border-normal--border-thick--brown--brown-bg--brown-text--cyan--cyan-bg--cyan-text--danger--danger-bg--danger-text--duration-base--ease-standard--fg-0--fg-1--fg-2--gray--gray-bg--gray-text--green--green-bg--green-text--info--info-bg--info-text--neutral--neutral-bg--neutral-text--orange--orange-bg--orange-text--pink--pink-bg--pink-text--purple--purple-bg--purple-text--radius-full--radius-md--red--red-bg--red-text--ring--space-1--space-2--space-3--space-5--success--success-bg--success-text--warn--warn-bg--warn-text--white--white-bg--white-text--yellow--yellow-bg--yellow-textSlots
The lid: whatever sits on top and slides.
The belly on the inline-start edge, filling the whole box and uncovered as the lid slides toward the end. Mirrors under RTL. Configure it with the host's startBehavior / startLatchAt / startCommitAt.
The belly on the inline-end edge, exposed by dragging toward the start. Configure it with the host's endBehavior / endLatchAt / endCommitAt.
The belly on the block-start edge, exposed by dragging the lid down. Configure it with the host's topBehavior / topLatchAt / topCommitAt.
The belly on the block-end edge, exposed by dragging the lid up. Configure it with the host's bottomBehavior / bottomLatchAt / bottomCommitAt.
Accessibility
Code
Directions, behaviors, and grouping
A single-direction reveal, a two-direction one pairing detail with a committing action, and a grouped stack where opening one closes the last.
<!-- One direction: slide the lid aside to read what's under it -->
<xtyle-reveal>
<article>Ada Lovelace · Analytical Engine notes</article>
<div slot="end">First published 1843</div>
</xtyle-reveal>
<!-- Two directions with different bellies, and a swipe that acts rather than opens -->
<xtyle-reveal latch-at="40%" end-behavior="commit" end-commit-at="0.7">
<article>Weekly digest</article>
<div slot="start">12 unread · 3 flagged</div>
<div slot="end"><button type="button">Archive</button></div>
</xtyle-reveal>
<!-- A grouped stack: sliding one closes whichever was open -->
<xtyle-reveal-group label="Products">
<xtyle-reveal name="products">
<article>Kettle</article>
<div slot="bottom">£49 · in stock</div>
</xtyle-reveal>
<xtyle-reveal name="products">
<article>Cafetière</article>
<div slot="bottom">£22 · in stock</div>
</xtyle-reveal>
</xtyle-reveal-group><script lang="ts">
import { Reveal, RevealGroup } from "@xtyle/svelte";
const products = [
{ name: "Kettle", price: "£49" },
{ name: "Cafetière", price: "£22" },
];
</script>
<Reveal latchAt="40%" endBehavior="commit" endCommitAt="0.7" onreveal={(d) => console.log(d.direction)}>
<article>Weekly digest</article>
<div slot="start">12 unread · 3 flagged</div>
<div slot="end"><button type="button">Archive</button></div>
</Reveal>
<!-- grouped: sliding one closes whichever was open -->
<RevealGroup label="Products">
{#each products as product}
<Reveal name="products">
<article>{product.name}</article>
<div slot="bottom">{product.price} · in stock</div>
</Reveal>
{/each}
</RevealGroup>---
import Reveal from "@xtyle/astro/Reveal.astro";
import RevealGroup from "@xtyle/astro/RevealGroup.astro";
import { FULL_TONES } from "../vocab.js";
const products = [
{ name: "Kettle", price: "£49" },
{ name: "Cafetière", price: "£22" },
];
---
<Reveal latchAt="40%" endBehavior="commit" endCommitAt="0.7">
<article>Weekly digest</article>
<div slot="start">12 unread · 3 flagged</div>
<div slot="end"><button type="button">Archive</button></div>
</Reveal>
<!-- grouped: sliding one closes whichever was open -->
<RevealGroup label="Products">
{products.map((product) => (
<Reveal name="products">
<article>{product.name}</article>
<div slot="bottom">{product.price} · in stock</div>
</Reveal>
))}
</RevealGroup>