Skip to main content
xriptxr

Reveal

Info:Layout
79

A lid that slides aside to expose a belly of detail or actions underneath.

swipe slide belly backdrop disclosure swipe actions drawer peek

Live demo

live · @xtyle/astro

Reveal

Reachable without a pointer

Tab to a lid and press Enter or Space : that takes the action, firing the same xtyle:reveal-commit a full pull fires. Arrow keys open a belly and Esc closes it, but opening a belly is not the same as reaching what is inside one — a commit direction's action has no other keyboard route. commit(direction) is the imperative equivalent, for a host or a harness.

control declares the lid a control rather than a container, so it announces as a button instead of a group. Opt in when the lid is the affordance; leave it off when the lid wraps controls of its own, since a button role would fold them into itself.

Travelling…
Info:reply

An incoming call

The whole point of the component in one box. Slide the lid right to answer, left to decline. The belly under each edge is already the color of its answer, so the box says what will happen before you commit to it. Both are behavior="commit", so a full pull acts and springs back rather than staying open.

Answer
Decline

A mail row, the way you would actually ship it

Grouped by name, so opening one closes the last. Sliding right latches a detail belly open to read; sliding left is endBehavior="both", so a short pull shows the action and a full pull just takes it.

Received 09:12 · 2 attachments
Archive
Received 08:40 · 2 attachments
Archive
Received Yesterday · 2 attachments
Archive

Box shapes

A shaped box is a sliding-top box: belly and lid are the same silhouette, and the lid moves as one whole shape rather than being cut as it goes. A shaped box drops its corner radius, and a toned belly drops its frame, since a straight edge cannot survive a cut one. Add contained to hold the lid inside the box's bounds instead of letting it travel clear; the last one here shows it.

underneath
underneath
underneath
underneath
underneath

Any silhouette, not just the named ones

shape takes a registered name or a clip-path value outright, so a box can be built from a shape the library has never heard of. Register more names with registerRevealShapes(), last-wins, the way the effect library takes verbs.

underneath
underneath

A lid carrying artwork

bleed lets the lid's content run to the edges with the grips floating over it, which is what a picture wants and text does not. These take gripStyle="dots", since a glyph reads as clutter over a picture; bar and none are the other two. The art is inline <svg> whose gradients read the named hue tokens, so these scenes recolor with the theme rather than being pinned to dead hex. Each option carries its own art, belly tones, and grip glyphs; sliding right latches the detail open, sliding left commits.

Restores 12 HP · costs 3 hours
Travel to the abbey
Trade goods · prices shift daily
Travel to the market
Catch supper · costs 2 hours
Travel to the river

Every direction, each saying what it does

All four bellies filled, each with its own tone and its own grip glyph, so every edge announces itself. Travel still locks to one axis, so it only ever goes one way at a time.

Add to basket
Remove
1.0L · variable temperature
Save for later

Opening without a grip

A tap opens a reveal, so gripStyle="none" costs the mark and not the pointer. With one belly a tap takes it; with several, the tap goes to whichever edge it landed nearest, and a tap on an open reveal closes it. open works the same way from markup, so a row can ship revealed or be driven by a consumer holding no handle on the element.

Opened by tap
Already revealed
This one shipped open

open="end" in the markup

Disabled

The lid is locked in place and the bellies are hidden entirely.

You should not see this

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.

Give a list row an end belly of actions and a start belly of detail, so one row answers both "what is this" and "what can I do with it".
Reach for behavior="both" when a belly's first action is the obvious one: the short pull shows the choices, the full pull takes the first without waiting.
Group a stack with a shared name when only one detail panel should be open at a time, and leave the name off when they are independent.
Wrap a group in <xtyle-reveal-group> to scope its names and give the set an accessible label; two lists on one page can then both use name="items".
Override the component.reveal fill to reshape the grips or the belly containers without touching the content either side of them.

Props

46 props, straight from the manifest.

PropTypeDefaultBindingsDescription
name string
html svelte astro
Groups this reveal with others sharing the name, so opening one closes the last, the way radios share a choice. Omit it and the reveal is independent. The name is scoped to the nearest <xtyle-reveal-group>, falling back to the document, so two unrelated lists can reuse a name without cross-talk.
open "start" | "end" | "top" | "bottom"
start end top bottom
html svelte astro
Which direction's belly is currently exposed. Set it to open one outright; absent means closed.
behavior "latch" | "commit" | "both"
latch commit both
latch
html svelte astro
What letting go of a slide means, for every direction unless one overrides it. 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.
shape string
html svelte astro
A silhouette to build the box from. Takes a registered name (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.
bleed boolean false
html svelte astro
Lets the lid's content reach the lid's edges instead of stepping aside for the grips, so a grip glyph floats over the content rather than pushing it inward. For a lid carrying artwork (an illustration, an inline <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.
control boolean false
html svelte astro
Declares the lid a control rather than a container, giving it 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.
contained boolean false
html svelte astro
Holds a shaped box's lid inside the box's bounds as it slides, cutting it off at the edge rather than letting it travel clear. Off by default, so a shaped box behaves like a sliding-top box: belly and lid are the same silhouette and the lid moves as one whole shape. Only meaningful alongside shape; an unshaped box always contains its lid.
tone FullTone
accent neutral danger success warn info accent-2 accent-3 accent-4 red orange yellow green blue purple brown pink cyan gray white black
html svelte astro
Paints every belly from one tone's token family (its fill from --{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.
flickVelocity html: flick-velocity number 0.4
html svelte astro
Pixels per millisecond above which a short fast flick latches regardless of how far it travelled, so a quick decisive swipe counts as intent the way a slow deliberate drag does.
travel number | string 0.7
html svelte astro
How far the lid slides when it opens, as a fraction of the box along that axis. The default leaves the lid holding onto the box rather than sliding off it entirely; 1 lets it come clear, and a smaller value suits a row that only needs to show an action. Overridable per direction.
gripStyle html: grip-style "glyph" | "bar" | "dots" | "none"
glyph bar dots none
glyph
html svelte astro
What each grip draws. 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 html: grip-size string var(--space-5)
html svelte astro
The size of the glyph in each grip. A bare bar can be tiny; an icon you must read before answering a call cannot.
gripPad html: grip-pad string var(--space-3)
html svelte astro
The breathing room around each grip glyph, which together with gripSize sets the grip's hit area.
latchAt html: latch-at number | string 0.4
html svelte astro
How far the lid must travel, as a fraction of the belly's own measured size, before letting go latches it open. Accepts a fraction (0.4) or a percentage (40%). A belly can override it for its own direction.
commitAt html: commit-at number | string 0.85
html svelte astro
How far the lid must travel before letting go fires the belly's action instead of latching. Only consulted for a commit or both belly. Same fraction-or-percentage shape as latchAt, and overridable per belly.
lockThreshold html: lock-threshold number 8
html svelte astro
Pixels of travel before the gesture commits to an axis. Until then nothing moves, so a near-vertical drag on a horizontal reveal scrolls the page instead of fighting it.
disabled boolean false
html svelte astro
Locks the lid in place and hides the bellies.
label string
html svelte astro
Accessible name for the lid, which is announced as a group carrying its expanded state.
startTone html: start-tone FullTone
accent neutral danger success warn info
html svelte astro
Overrides tone for the start belly alone, which is how one box declines in red and accepts in green.
startGrip html: start-grip string
html svelte astro
The roster glyph drawn in the start grip, so each edge says what it does. Any name the icon roster can draw, including one a mod contributed through the xtyle.icons slot.
endTone html: end-tone FullTone
accent neutral danger success warn info
html svelte astro
Overrides tone for the end belly alone, which is how one box declines in red and accepts in green.
endGrip html: end-grip string
html svelte astro
The roster glyph drawn in the end grip, so each edge says what it does. Any name the icon roster can draw, including one a mod contributed through the xtyle.icons slot.
topTone html: top-tone FullTone
accent neutral danger success warn info
html svelte astro
Overrides tone for the top belly alone, which is how one box declines in red and accepts in green.
topGrip html: top-grip string
html svelte astro
The roster glyph drawn in the top grip, so each edge says what it does. Any name the icon roster can draw, including one a mod contributed through the xtyle.icons slot.
bottomTone html: bottom-tone FullTone
accent neutral danger success warn info
html svelte astro
Overrides tone for the bottom belly alone, which is how one box declines in red and accepts in green.
bottomGrip html: bottom-grip string
html svelte astro
The roster glyph drawn in the bottom grip, so each edge says what it does. Any name the icon roster can draw, including one a mod contributed through the xtyle.icons slot.
startTravel html: start-travel number | string
html svelte astro
Overrides travel for the start direction alone.
endTravel html: end-travel number | string
html svelte astro
Overrides travel for the end direction alone.
topTravel html: top-travel number | string
html svelte astro
Overrides travel for the top direction alone.
bottomTravel html: bottom-travel number | string
html svelte astro
Overrides travel for the bottom direction alone.
startGripStyle html: start-grip-style "glyph" | "bar" | "dots" | "none"
glyph bar dots none
html svelte astro
Overrides gripStyle for the start direction alone.
endGripStyle html: end-grip-style "glyph" | "bar" | "dots" | "none"
glyph bar dots none
html svelte astro
Overrides gripStyle for the end direction alone.
topGripStyle html: top-grip-style "glyph" | "bar" | "dots" | "none"
glyph bar dots none
html svelte astro
Overrides gripStyle for the top direction alone.
bottomGripStyle html: bottom-grip-style "glyph" | "bar" | "dots" | "none"
glyph bar dots none
html svelte astro
Overrides gripStyle for the bottom direction alone.
startBehavior html: start-behavior "latch" | "commit" | "both"
latch commit both
html svelte astro
Overrides behavior for the start direction alone.
startLatchAt html: start-latch-at number | string
html svelte astro
Overrides latchAt for the start direction alone.
startCommitAt html: start-commit-at number | string
html svelte astro
Overrides commitAt for the start direction alone.
endBehavior html: end-behavior "latch" | "commit" | "both"
latch commit both
html svelte astro
Overrides behavior for the end direction alone.
endLatchAt html: end-latch-at number | string
html svelte astro
Overrides latchAt for the end direction alone.
endCommitAt html: end-commit-at number | string
html svelte astro
Overrides commitAt for the end direction alone.
topBehavior html: top-behavior "latch" | "commit" | "both"
latch commit both
html svelte astro
Overrides behavior for the top direction alone.
topLatchAt html: top-latch-at number | string
html svelte astro
Overrides latchAt for the top direction alone.
topCommitAt html: top-commit-at number | string
html svelte astro
Overrides commitAt for the top direction alone.
bottomBehavior html: bottom-behavior "latch" | "commit" | "both"
latch commit both
html svelte astro
Overrides behavior for the bottom direction alone.
bottomLatchAt html: bottom-latch-at number | string
html svelte astro
Overrides latchAt for the bottom direction alone.
bottomCommitAt html: bottom-commit-at number | string
html svelte astro
Overrides 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.

EventDetailBindingsDescription
xtyle:reveal svelte: onreveal { direction }
html svelte astro
A belly was exposed.
xtyle:conceal svelte: onconceal { direction }
html svelte astro
The lid closed over whichever belly was open.
xtyle:reveal-commit svelte: oncommit { direction }
html svelte astro
A direction's action fired — a full pull past its threshold, 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.

MethodReturnsBindingsDescription
reveal(direction: "start" | "end" | "top" | "bottom") void
html svelte
Slide the lid open on a direction, exactly as a pull past its latchAt does. Ignored for a direction with no belly, and on a disabled reveal.
conceal() void
html svelte
Slide the lid back over whatever is open, exactly as letting go short of the threshold does.
commit(direction: "start" | "end" | "top" | "bottom") void
html svelte
Take a direction's action and close, exactly as a full pull past its 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

.xtyle-reveal--open

A belly is exposed; the modifier names which direction.

grouped

.xtyle-reveal--grouped

The reveal carries a name, so opening it closes its peers.

disabled

.xtyle-reveal--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

Success:::part(lid) .xtyle-reveal__lid

The lid: the sliding surface holding the default slot's content. Focusable, and the target of the drag.

belly

Success:::part(belly) .xtyle-reveal__belly

What sits under the lid in one direction, revealed as the lid slides off it.

grip

Success:::part(grip) .xtyle-reveal__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.

Success:fully covered 79/79 consumed tokens produced default register: 310 tokens

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-text

Slots

default
html svelte astro

The lid: whatever sits on top and slides.

start
html svelte astro

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.

end
html svelte astro

The belly on the inline-end edge, exposed by dragging toward the start. Configure it with the host's endBehavior / endLatchAt / endCommitAt.

top
html svelte astro

The belly on the block-start edge, exposed by dragging the lid down. Configure it with the host's topBehavior / topLatchAt / topCommitAt.

bottom
html svelte astro

The belly on the block-end edge, exposed by dragging the lid up. Configure it with the host's bottomBehavior / bottomLatchAt / bottomCommitAt.

Accessibility

The lid is focusable and announced as a group carrying aria-expanded, so the disclosure is legible without a pointer.
Arrow keys open the belly on the matching edge and Escape closes whichever is open. Enter and Space take the action: they fire the same xtyle:reveal-commit a full pull does, on the open direction, or on the sole live one when nothing is open and there is no ambiguity about which action was meant. A latch direction has no action behind it — being open is the whole interaction — so there they open and close instead.
control declares the lid a control rather than a container, swapping role="group" for role="button". 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, and announcing it as a group describes the furniture instead of the affordance. It is opt-in because the lid takes whatever you slot into it: a lid holding its own buttons is genuinely a container, and a button role there would fold its children into itself. Pair it with label.
Opening a belly is not the same as reaching what is inside it. A commit direction's action was once reachable only by dragging, which made the lid's tabstop a stop that led nowhere; Enter is the keyboard equivalent of the pull, and commit(direction) is the imperative one for a host or a test harness.
A concealed belly is inert, keeping its controls out of the tab order until it is actually on screen.
When a grouped reveal is closed by a sibling opening, focus lands on its own lid rather than being dropped to the document.
Travel locks to one axis after lockThreshold pixels, so a vertical scroll gesture on a horizontal reveal still scrolls the page.
The slide honors prefers-reduced-motion, landing in the same place with the travel skipped.

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 &middot; 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 &middot; 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 &middot; in stock</div>
	</xtyle-reveal>
	<xtyle-reveal name="products">
		<article>Cafetière</article>
		<div slot="bottom">£22 &middot; in stock</div>
	</xtyle-reveal>
</xtyle-reveal-group>