component
TuxSlideover
TuxModal — slides in from a viewport edge, preserves the reading context behind the scrim. Built on the native <dialog> element so focus trap + escape + scrim come from the platform. Slide animation rides Batch J's --ease-corridor curve. Three sides: right (default, row detail and filters), left (mobile nav), bottom (action sheet). right edge
Row detail (default)
The default posture. Use for clicking a TuxRichDataGrid row to inspect its full record, or for the "details" pane of a list view. Width defaults to 28rem; override via the size prop for wider panels (e.g. a side-by-side editor).
<TuxSlideover v-model="open" title="Field details" eyebrow="schema">
<p>Body content scrolls here.</p>
<template #footer>
<TuxButton intent="ghost" @click="open = false">Cancel</TuxButton>
<TuxButton intent="primary">Save</TuxButton>
</template>
</TuxSlideover>left edge
Mobile nav drawer
Symmetric to the right variant — slides from the left. The style-guide shell uses a similar pattern for the mobile sidebar reveal; this component packages the affordance so a consuming app doesn't reinvent the trap-focus + animation stack.
<TuxSlideover v-model="open" side="left" title="Navigation drawer">
…mobile-style nav reveal…
</TuxSlideover>bottom edge
Action sheet
Phone-style action sheet. Slides up from the bottom edge of the viewport; the panel takes full viewport width and the configured size (height). Use for quick actions that don't deserve a full modal — bulk row operations, "share" sheets, sort controls.
<TuxSlideover v-model="open" side="bottom" title="Quick actions">
…action sheet…
</TuxSlideover>canonical use
Filter panel
The most common posture in a real app — clicking a "Filter" button on a list view opens a right-edge panel of filter controls, with Reset / Apply at the footer. The panel preserves the catalog context behind the scrim so users can see what they're filtering against.
2 tiers, all format <TuxSlideover v-model="filterOpen" title="Filters" eyebrow="catalog">
<fieldset>
<legend class="eyebrow">classification tier</legend>
<label v-for="t in tiers" :key="t.value">
<input type="checkbox" :value="t.value" v-model="filters.tier" />
{{ t.label }}
</label>
</fieldset>
<!-- more filter fields… -->
<template #footer>
<TuxButton intent="ghost" @click="filters.tier = []">Reset</TuxButton>
<TuxButton intent="primary" @click="filterOpen = false">Apply</TuxButton>
</template>
</TuxSlideover>props
Props
v-model— open / closed. Boolean.side—"left" | "right" | "bottom". Defaults"right".size— CSS length for the panel width (left/right) or height (bottom). Defaults28rem(left/right) or24rem(bottom).title— header heading. Pair witheyebrowabove it.eyebrow— uppercase mini-label above the title.showClose— top-right close button. Defaultstrue.closeOnBackdrop— dismiss when scrim is clicked. Defaultstrue.- Slots: default (body),
#header(replace eyebrow + title region),#footer(action row). - Exposes
open()+close()via template ref.
when to reach for which
Slideover vs Modal
- TuxSlideover — user is drilling into the page they're on. Row detail, filter panel, side-by-side editor. Context behind the scrim is still relevant.
- TuxModal — the page below doesn't matter. Confirmation, full-attention form, fatal error. Center-screen makes the page recede.
- Both ship the native dialog primitives — focus trap, escape, scrim. Choose based on whether the underlying page is part of the user's mental model for the current action.