Skip to content

TicFrame v5.7.0-alpha.1 is available - read the changelog.

TicFrame

Components

Drawer

tf-drawer and tf-sheet are the ready-made panel treatments for the Offcanvas trigger/backdrop behavior — a drawer slides in from the side, a sheet slides up from the bottom.

How It Works

Give any element tf-drawer or tf-sheet and pair it with a data-tf-toggle="offcanvas" trigger — the classes only supply positioning, size, and the slide transition. Everything else (backdrop, focus trap, Escape, scroll lock) comes from Offcanvas.

Drawer vs. sheet

tf-drawer is anchored to the inline-end edge (right in LTR, left in RTL) and slides horizontally. tf-sheet is anchored to the bottom edge, spans full width, and slides vertically — the mobile-native pattern.

RTL

A drawer's slide direction mirrors automatically under dir="rtl" — no separate class needed. A sheet is unaffected by direction since it moves vertically.

Keyboard model

Identical to Offcanvas: Escape closes, Tab is trapped inside while open, focus returns to the trigger on close.

Sizing

A drawer defaults to min(28rem, 90vw) wide. A sheet is always full width and caps its height at 85dvb so tall content scrolls internally instead of overflowing the viewport.

Live Examples

Drawer (default, side-anchored)

Slides in from the inline-end edge.

HTML
<button type="button" class="tf-btn tf-btn-primary" data-tf-toggle="offcanvas" data-tf-target="#drawer-basic">Open drawer</button>
<aside id="drawer-basic" class="tf-drawer" aria-label="Basic drawer">
  <button type="button" class="tf-btn tf-btn-icon tf-btn-ghost" data-tf-dismiss="offcanvas" aria-label="Close drawer"><i class="ti ti-028069" aria-hidden="true"></i></button>
  <p>Slides from the inline-end edge; mirrors under RTL automatically.</p>
</aside>

Sheet (bottom-anchored)

Full width, slides up from the bottom, rounded top corners only — the mobile-native pattern. Try it at a narrow viewport width.

HTML
<button type="button" class="tf-btn tf-btn-primary" data-tf-toggle="offcanvas" data-tf-target="#sheet-basic">Open sheet</button>
<aside id="sheet-basic" class="tf-sheet" aria-label="Basic sheet">
  <button type="button" class="tf-btn tf-btn-icon tf-btn-ghost" data-tf-dismiss="offcanvas" aria-label="Close sheet"><i class="ti ti-028069" aria-hidden="true"></i></button>
  <p>Anchored to the bottom edge, full width, rounded top corners.</p>
</aside>

Drawer with header/body/footer structure

A drawer is unopinionated about internal layout — compose it with ordinary utilities for a header, scrollable body, and footer.

HTML
<aside id="drawer-structured" class="tf-drawer tf-flex tf-flex-col" aria-label="Shopping cart">
  <div class="tf-flex tf-items-center tf-justify-between tf-pb-4 tf-mb-4">
    <h4><i class="ti ti-022275" aria-hidden="true"></i> Your cart</h4>
    <button type="button" data-tf-dismiss="offcanvas" aria-label="Close cart"><i class="ti ti-028069" aria-hidden="true"></i></button>
  </div>
  <div class="tf-flex-1 tf-stack">...line items...</div>
  <div><button type="button" class="tf-btn tf-btn-primary tf-w-full">Checkout</button></div>
</aside>

States

A drawer has two states, reflected on the panel itself and readable by both CSS and script.

StateHow it's represented
Closedhidden attribute present; translated fully off-screen so it doesn't participate in layout or focus order.
Openhidden removed; translated to 0, focus moved inside, backdrop present.
Dismiss button focusStandard :focus-visible ring — no drawer-specific override.
Trigger disabledA disabled trigger button does not open the drawer, same as any native disabled control.

Accessibility

RequirementTicFrame guidance
NameAdd aria-label or aria-labelledby on the drawer/sheet element.
Role and focusInherited entirely from Offcanvas — see the Offcanvas accessibility table.
Reduced motionThe slide transition respects prefers-reduced-motion through the shared --tf-duration-normal token.

API Reference

Classes

ClassPurpose
tf-drawerSide-anchored panel, slides horizontally.
tf-sheetBottom-anchored panel, slides vertically, full width, rounded top corners.

Attributes, methods, and events are the same as Offcanvas — see the Offcanvas API reference.

CSS Variables

TokenDefaultPurpose
--tf-z-modal1300Drawer/sheet stacking order.
--tf-shadow-2Elevation shadow tokenPanel shadow.
--tf-radius-6Large radius tokenSheet's top-corner rounding.
--tf-space-6Spacing tokenPanel padding.
--tf-duration-normal200msSlide transition duration.

Troubleshooting

SymptomFix
Sheet slides from the side instead of the bottomMake sure you're on TicFrame 5.7.0-alpha.1 or later — earlier alpha builds shared drawer's side-slide CSS for tf-sheet.
Drawer doesn't slide, just appears/disappearsDon't toggle display yourself; let TicFrame manage the hidden attribute so the translate transition can run.
Sheet content is cut off on short viewportsContent taller than 85dvb scrolls internally — the sheet itself has overflow: auto, so no extra markup is needed.
Drawer opens on the wrong side under RTLThis is expected: it mirrors automatically. If you need a fixed side regardless of direction, override inset-inline-end with a physical right/left value.