Components · Feedback
Drawer
A side panel that slides in for a longer edit or detail view — rendered through the shared Drawer.
Examples
<!-- Paste-and-run: save as .html and open in a browser. No build step, no bundler.
Drawer is a COMPOSITE (antd, no framework-free element), so its HTML form is a
CDN-React page — React + antd load from a CDN (esm.sh) and mount on open. It
consumes the SAME shared `drawerTheme` the React/Vue wrappers use, so it renders
the DS V3 look (white panel, ink title). Keeps antd's built-in slide motion.
No JSX here (JSX needs a compiler) — we use React.createElement via the `h` alias. -->
<div id="root"></div>
<script type="module">
import React from 'https://esm.sh/react@18';
import { createRoot } from 'https://esm.sh/react-dom@18/client';
import { ConfigProvider, Drawer, Button, Space } from 'https://esm.sh/antd@6?deps=react@18,react-dom@18';
import { drawerTheme } from 'https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/drawer-theme.js';
const h = React.createElement;
const { useState } = React;
// Matrix: placement (top | right | bottom | left) × size (default 378 · large 736 for left/right).
const placement = 'right'; // right for settings/edit; bottom for mobile-style sheets
const size = 'default'; // 'large' → wider panel (736 for left/right)
const horiz = placement === 'left' || placement === 'right';
const dim = horiz ? { width: size === 'large' ? 736 : 378 } : { height: size === 'large' ? 480 : 300 };
function App() {
const [open, setOpen] = useState(false);
return h(ConfigProvider, { theme: drawerTheme },
h(Button, { type: 'primary', onClick: () => setOpen(true) }, 'Slide settings'),
h(Drawer, {
open,
title: 'Slide settings',
placement,
...dim,
mask: true, // mask + scroll-lock the page (antd default)
closable: true, // header close (X)
onClose: () => setOpen(false),
footer: h(Space, null, h(Button, { onClick: () => setOpen(false) }, 'Cancel'), h(Button, { type: 'primary' }, 'Save changes')),
}, h('p', null, 'Adjust how this slide behaves for your audience.'))
);
}
// Same shared theme the React/Vue wrappers pass to ConfigProvider.
createRoot(document.getElementById('root')).render(h(App));
</script>
import { useState } from 'react';
import { ConfigProvider, Drawer, Button, Space } from 'antd'; // antd v6
import { drawerTheme } from '@ahaslides-product/design/drawer-theme';
function SlideSettings() {
const [open, setOpen] = useState(false);
// Matrix: placement (top | right | bottom | left) × size (default 378 · large 736 for left/right).
const placement = 'right'; // right for settings/edit; bottom for mobile-style sheets
const size = 'default'; // 'large' → wider panel (736 for left/right)
const horiz = placement === 'left' || placement === 'right';
const dim = horiz ? { width: size === 'large' ? 736 : 378 } : { height: size === 'large' ? 480 : 300 };
return (
<ConfigProvider theme={drawerTheme}>
<Button type="primary" onClick={() => setOpen(true)}>Slide settings</Button>
<Drawer
open={open}
title="Slide settings"
placement={placement}
{...dim}
mask /* mask + scroll-lock the page (antd default) */
closable /* header close (X) */
onClose={() => setOpen(false)}
footer={<Space><Button onClick={() => setOpen(false)}>Cancel</Button><Button type="primary">Save changes</Button></Space>}
>
<p>Adjust how this slide behaves for your audience.</p>
</Drawer>
</ConfigProvider>
);
}
// One shared drawerTheme → the DS V3 look; keeps antd's built-in slide motion.
<script setup>
import { ref } from 'vue';
import { ConfigProvider, Drawer, Button, Space } from 'ant-design-vue'; // ant-design-vue v4
import { drawerTheme } from '@ahaslides-product/design/drawer-theme';
const open = ref(false);
// Matrix: placement (top | right | bottom | left) × size (default 378 · large 736 for left/right).
const placement = 'right'; // right for settings/edit; bottom for mobile-style sheets
const size = 'default'; // 'large' → wider panel (736 for left/right)
</script>
<template>
<a-config-provider :theme="drawerTheme">
<a-button type="primary" @click="open = true">Slide settings</a-button>
<a-drawer
v-model:open="open"
title="Slide settings"
:placement="placement"
:width="(placement === 'left' || placement === 'right') ? (size === 'large' ? 736 : 378) : undefined"
:height="(placement === 'top' || placement === 'bottom') ? (size === 'large' ? 480 : 300) : undefined"
:mask="true"
:closable="true"
>
<p>Adjust how this slide behaves for your audience.</p>
<template #footer>
<a-space>
<a-button @click="open = false">Cancel</a-button>
<a-button type="primary">Save changes</a-button>
</a-space>
</template>
</a-drawer>
</a-config-provider>
</template>
<!-- The SAME drawerTheme as React → one DS V3 look across both vendor libraries. -->
// @ahaslides-product/design/drawer-theme — declared ONCE, consumed by both tiers.
import { drawerTheme } from '@ahaslides-product/design/drawer-theme';
export const drawerTheme = {
token: {
colorPrimary: '#6A1EBB',
borderRadius: 8,
colorText: '#1A1A1A',
colorTextHeading: '#1A1A1A',
colorBgElevated: '#FFFFFF',
fontFamily: 'var(--aha-font-product, "Plus Jakarta Sans", sans-serif)',
},
components: {
Drawer: {
colorBgElevated: '#FFFFFF', // white panel surface
colorText: '#1A1A1A',
},
},
};
API
| Prop | Type | Default | Notes |
|---|---|---|---|
open | boolean | false | Controls visibility |
title | string | — | Panel heading |
placement | top | right | bottom | left | right | Which edge it slides from |
width | number | string | 378 | Panel width for left/right (large ≈ 736) |
height | number | string | 378 | Panel height for top/bottom (large ≈ 480) |
size | default | large | default | antd preset size (378/736 l·r); the DS default is 378 |
footer | ReactNode | — | Pinned actions row (keep the primary action here) |
mask | boolean | true | Dim + scroll-lock the page behind the panel |
closable | boolean | true | Show the header close (X) |
onClose | () => void | — | Dismiss handler |
Install
# .npmrc — once: point the @ahaslides-product scope at GitHub Packages
@ahaslides-product:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN} # a GitHub token with read:packages
npm i @ahaslides-product/design
import '@ahaslides-product/design/tokens.css'; // once, at the app root
import '@ahaslides-product/design/drawer-theme'; // registers <drawer>
Agent feed for this component (absolute, fetchable anywhere): drawer.agent.json · drawer.md · drawer.llms.txt
When to use
When to use
- Drawer — a longer edit form or detail panel where keeping page context matters
- Modal — a short, blocking decision the user must complete first
- a page — the task is large enough to deserve its own route
Give it a clear title and keep the primary action pinned in a footer. Right placement for settings/edit; bottom for mobile-style sheets.
Surfaces
editor dashboard settings
Spec
Panel white surface, slides from the right (or any edge) · Title ink #1A1A1A · SemiBold · Body 24 padding · ink text · Mask ink overlay rgba(26,26,46,.7) · Motion antd's built-in slide enter/leave (kept)