Components · Data Entry
InputNumber
Enter a number with steppers, min/max and precision — quantities, limits, durations — rendered through the shared InputNumber.
Examples
<!-- Paste-and-run: save as .html and open in a browser. No build step, no bundler.
InputNumber 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 `inputNumberTheme` the React/Vue wrappers use, so it renders the DS V3 look
(32px field, radius 8, #E3E3E3 border, brand focus/hover).
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, InputNumber } from 'https://esm.sh/antd@6?deps=react@18,react-dom@18';
import { inputNumberTheme } from 'https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/input-number-theme.js';
const h = React.createElement;
const w = { width: 200 };
createRoot(document.getElementById('root')).render(
h(ConfigProvider, { theme: inputNumberTheme },
h('div', { style: { display: 'flex', flexDirection: 'column', gap: 16 } },
// Default (32) · small (24) · large (40)
h(InputNumber, { min: 0, max: 100, defaultValue: 3, style: w }),
h(InputNumber, { size: 'small', min: 0, max: 100, defaultValue: 3, style: w }),
h(InputNumber, { size: 'large', min: 0, max: 100, defaultValue: 3, style: w }),
// Status: error · warning
h(InputNumber, { status: 'error', defaultValue: 120, max: 100, style: w }),
h(InputNumber, { status: 'warning', defaultValue: 95, max: 100, style: w }),
// Precision + affixes; steppers off; disabled / read-only
h(InputNumber, { prefix: '$', min: 0, step: 0.01, precision: 2, defaultValue: 19.99, style: w }),
h(InputNumber, { addonBefore: 'Every', addonAfter: 'min', min: 0, defaultValue: 30, style: { width: 240 } }),
h(InputNumber, { controls: false, defaultValue: 42, style: w }),
h(InputNumber, { disabled: true, defaultValue: 3, style: w }),
h(InputNumber, { readOnly: true, defaultValue: 3, style: w })
)
)
);
</script>
import { ConfigProvider, InputNumber } from 'antd'; // antd v6
import { inputNumberTheme } from '@ahaslides-product/design/input-number-theme';
<ConfigProvider theme={inputNumberTheme}>
{/* Default field — size default (32), steppers on */}
<InputNumber min={0} max={100} defaultValue={3} onChange={setCount} style={{ width: 200 }} />
{/* Sizes: small (24) · large (40) */}
<InputNumber size="small" min={0} max={100} defaultValue={3} style={{ width: 200 }} />
<InputNumber size="large" min={0} max={100} defaultValue={3} style={{ width: 200 }} />
{/* Status: error · warning */}
<InputNumber status="error" defaultValue={120} max={100} style={{ width: 200 }} />
<InputNumber status="warning" defaultValue={95} max={100} style={{ width: 200 }} />
{/* Precision + affixes; steppers off; disabled / read-only */}
<InputNumber prefix="$" min={0} step={0.01} precision={2} defaultValue={19.99} style={{ width: 200 }} />
<InputNumber addonBefore="Every" addonAfter="min" min={0} defaultValue={30} style={{ width: 240 }} />
<InputNumber controls={false} defaultValue={42} style={{ width: 200 }} />
<InputNumber disabled defaultValue={3} style={{ width: 200 }} />
<InputNumber readOnly defaultValue={3} style={{ width: 200 }} />
</ConfigProvider>
// One shared inputNumberTheme → the DS V3 look; set min/max to constrain, not post-validation.
<script setup>
import { ref } from 'vue';
import { ConfigProvider, InputNumber } from 'ant-design-vue'; // ant-design-vue v4
import { inputNumberTheme } from '@ahaslides-product/design/input-number-theme';
const count = ref(3);
</script>
<template>
<a-config-provider :theme="inputNumberTheme">
<!-- Default field — size default (32), steppers on -->
<a-input-number v-model:value="count" :min="0" :max="100" style="width: 200px" />
<!-- Sizes: small (24) · large (40) -->
<a-input-number size="small" :min="0" :max="100" :value="3" style="width: 200px" />
<a-input-number size="large" :min="0" :max="100" :value="3" style="width: 200px" />
<!-- Status: error · warning -->
<a-input-number status="error" :value="120" :max="100" style="width: 200px" />
<a-input-number status="warning" :value="95" :max="100" style="width: 200px" />
<!-- Precision + affixes; steppers off; disabled / read-only -->
<a-input-number prefix="$" :min="0" :step="0.01" :precision="2" :value="19.99" style="width: 200px" />
<a-input-number addon-before="Every" addon-after="min" :min="0" :value="30" style="width: 240px" />
<a-input-number :controls="false" :value="42" style="width: 200px" />
<a-input-number disabled :value="3" style="width: 200px" />
<a-input-number :read-only="true" :value="3" style="width: 200px" />
</a-config-provider>
</template>
<!-- The SAME inputNumberTheme as React → one DS V3 look across both vendor libraries. -->
// @ahaslides-product/design/input-number-theme — declared ONCE, consumed by both tiers.
import { inputNumberTheme } from '@ahaslides-product/design/input-number-theme';
export const inputNumberTheme = {
token: {
colorPrimary: '#6A1EBB',
borderRadius: 8,
controlHeight: 32,
colorBorder: '#E3E3E3',
colorTextPlaceholder: '#8A8A8A',
fontFamily: 'var(--aha-font-product, "Plus Jakarta Sans", sans-serif)',
},
components: {
InputNumber: {
activeBorderColor: '#6A1EBB', // brand focus border
hoverBorderColor: '#D3B4FF', // purple-30 hover border
borderRadius: 8,
controlHeight: 32,
},
},
};
API
| Prop | Type | Default | Notes |
|---|---|---|---|
value | number | — | Controlled numeric value |
size | 'small' | 'middle' | 'large' | 'middle' | Field height: small 24 · default 32 · large 40 |
status | 'error' | 'warning' | — | Validation state — coloured border/glow |
min | number | -Infinity | Lower bound |
max | number | Infinity | Upper bound |
step | number | 1 | Increment for steppers / arrow keys |
precision | number | — | Fixed decimal places |
controls | boolean | true | Show the up/down steppers |
disabled | boolean | false | Non-interactive, greyed field |
readOnly | boolean | false | Value visible but not editable |
prefix | ReactNode | — | Inline leading affix (e.g. $) |
addonBefore | ReactNode | — | Attached leading label |
addonAfter | ReactNode | — | Attached trailing label (e.g. unit) |
onChange | (value) => void | — | Fires with the new number |
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/input-number-theme'; // registers <input-number>
Agent feed for this component (absolute, fetchable anywhere): input-number.agent.json · input-number.md · input-number.llms.txt
When to use
When to use
- InputNumber — a bounded numeric quantity — a limit, a count, a duration where steppers help
- Slider — an approximate value across a known range where the exact number matters less
- Input type=number — a free number with no bounds or steppers — but prefer InputNumber for validity
Set min/max to the real limits so the field constrains instead of validating after the fact. Pre-fill a sensible default rather than empty; use precision for currency/percentages.
Surfaces
editor dashboard settings
Spec
Field height 32 (md) · radius 8 · 1px #E3E3E3 border · Sizes small 24 · default 32 · large 40 · font 14 · Hover #D3B4FF (purple-30) border · Focus brand #6A1EBB border · Status error #F5222D · warning border/glow · Steppers up/down on hover; keyboard ↑ ↓; toggle via controls · Placeholder #8A8A8A