Components · Data Entry
Form
A labelled, validated set of fields — sign-in, settings, create dialogs — rendered through the shared Form.
Examples
<!-- Paste-and-run: save as .html and open in a browser. No build step, no bundler.
Form 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 `formTheme` the React/Vue wrappers use, so it renders
the DS V3 look (32px controls, radius 8, #E3E3E3 border, brand primary submit).
Matrix props: layout (vertical|horizontal|inline) · size (small|default|large) ·
disabled · requiredMark · per-Item validation (error|warning|success) + help text.
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, Form, Input, Button } from 'https://esm.sh/antd@6?deps=react@18,react-dom@18';
import { formTheme } from 'https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/form-theme.js';
const h = React.createElement;
const Item = Form.Item;
createRoot(document.getElementById('root')).render(
h(ConfigProvider, { theme: formTheme },
h(Form, { layout: 'vertical', size: 'default', disabled: false, requiredMark: true,
style: { maxWidth: 360 }, initialValues: { name: 'AhaSlides' }, onFinish: (v) => console.log(v) },
h(Item, { label: 'Workspace name', name: 'name', rules: [{ required: true }] }, h(Input, { placeholder: 'AhaSlides' })),
// Validation state — error | warning | success — colours the border + shows help text
h(Item, { label: 'Contact email', name: 'email', rules: [{ type: 'email', required: true, message: 'Enter a valid email — e.g. you@company.com' }] }, h(Input, { placeholder: 'you@company.com' })),
h(Item, null, h(Button, { type: 'primary', htmlType: 'submit' }, 'Save changes'))
)
)
);
</script>
import { ConfigProvider, Form, Input, Button } from 'antd'; // antd v6
import { formTheme } from '@ahaslides-product/design/form-theme';
// layout: vertical | horizontal | inline · size: small | default | large · disabled toggles the whole form
<ConfigProvider theme={formTheme}>
<Form layout="vertical" size="default" disabled={false} requiredMark
initialValues={{ name: 'AhaSlides' }} onFinish={save}>
<Form.Item label="Workspace name" name="name" rules={[{ required: true }]}>
<Input placeholder="AhaSlides" />
</Form.Item>
{/* Validation state — error | warning | success — colours the border + shows help text */}
<Form.Item label="Contact email" name="email"
rules={[{ type: 'email', required: true, message: 'Enter a valid email — e.g. you@company.com' }]}>
<Input placeholder="you@company.com" />
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit">Save changes</Button>
</Form.Item>
</Form>
</ConfigProvider>
// One shared formTheme → the DS V3 look; labels above the field, one primary submit.
<script setup>
import { reactive } from 'vue';
import { ConfigProvider, Form, FormItem, Input, Button } from 'ant-design-vue'; // ant-design-vue v4
import { formTheme } from '@ahaslides-product/design/form-theme';
const model = reactive({ name: 'AhaSlides', email: '' });
</script>
<!-- layout: vertical | horizontal | inline · size: small | default | large · disabled toggles the whole form -->
<template>
<a-config-provider :theme="formTheme">
<a-form layout="vertical" size="default" :disabled="false" required-mark :model="model" @finish="save">
<a-form-item label="Workspace name" name="name" :rules="[{ required: true }]">
<a-input v-model:value="model.name" placeholder="AhaSlides" />
</a-form-item>
<!-- Validation state — error | warning | success — colours the border + shows help text -->
<a-form-item label="Contact email" name="email"
:rules="[{ type: 'email', required: true, message: 'Enter a valid email — e.g. you@company.com' }]">
<a-input v-model:value="model.email" placeholder="you@company.com" />
</a-form-item>
<a-form-item>
<a-button type="primary" html-type="submit">Save changes</a-button>
</a-form-item>
</a-form>
</a-config-provider>
</template>
<!-- The SAME formTheme as React → one DS V3 look across both vendor libraries. -->
// @ahaslides-product/design/form-theme — declared ONCE, consumed by both tiers.
import { formTheme } from '@ahaslides-product/design/form-theme';
export const formTheme = {
token: {
colorPrimary: '#6A1EBB',
borderRadius: 8,
controlHeight: 32,
colorBorder: '#E3E3E3',
colorTextPlaceholder: '#8A8A8A',
colorError: '#F5222D',
fontFamily: 'var(--aha-font-product, "Plus Jakarta Sans", sans-serif)',
},
components: {
Form: { labelColor: '#4A4A4A', itemMarginBottom: 20, verticalLabelPadding: '0 0 4px' },
Input: { borderRadius: 8, controlHeight: 32 },
Button: { borderRadius: 8, controlHeight: 32 },
},
};
API
| Prop | Type | Default | Notes |
|---|---|---|---|
layout | vertical | horizontal | inline | vertical | Label placement |
size | small | default | large | default | Control height for every field (24 / 32 / 40) |
fields | FormItem[] | [] | name / label / rules / control per row |
requiredMark | boolean | 'optional' | true | Show the required asterisk (or mark optional fields instead) |
validateStatus | error | warning | success | validating | — | Per-Form.Item validation state — coloured border + help text |
initialValues | object | — | Seed values |
onFinish | (values) => void | — | Fires on a valid submit |
disabled | boolean | false | Disables the whole form |
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/form-theme'; // registers <form>
Agent feed for this component (absolute, fetchable anywhere): form.agent.json · form.md · form.llms.txt
When to use
When to use
- Form — two or more related fields submitted together, with validation
- a single Input/Select — one value that applies on its own — no submit step
- Settings pattern — a settings surface — see the Settings pattern for grouping and spacing
Label every field with a noun phrase above the control (vertical layout reads best on narrow surfaces). Validate on blur and on submit; show the error below the field with how to fix it. One primary submit per form.
Surfaces
editor dashboard settings
Spec
Controls height 32 · radius 8 · 1px #E3E3E3 border · Label #4A4A4A, above the field (vertical layout) · Submit primary Button #6A1EBB · Error #F5222D border + message below the field · Item gap 20px between items · Size control height 24 (small) · 32 (default) · 40 (large) · Validation error / warning / success — coloured border + help text