Theme
Version
GitHub PyPI Discord
On this page

NumberInput

Use CNumberInput for a quantity where incrementing and decrementing make sense: item counts, measurements, thresholds, or bounded settings. Its public value is an exact canonical decimal string, so 0.1 stays 0.1 instead of becoming a JavaScript binary-float approximation.

Use CPinInput for one-time codes and identifiers. A credit-card number, postal code, account number, or phone number is text, not a quantity.

Edit a quantity

Compose NumberInput inside CField for a visible label, description, error, and shared state.

<c-CField required>
  <c-fill name="label">Crates</c-fill>
  <c-fill name="description">Choose from 1 through 20.</c-fill>
  <c-fill name="default">
    <c-CNumberInput name="crates" value="2" min="1" max="20" />
  </c-fill>
</c-CField>
Edit and submit a quantity
Show code
from decimal import Decimal
from typing import Any

import citry_ui
from citry import Component, citry
from citry_ui import CNumberInput

citry.register_library(citry_ui)


class BasicNumberInput(Component):
    class Kwargs:
        pass

    class Slots:
        pass

    def template_data(self, kwargs: Kwargs, slots: Slots) -> dict[str, Any]:  # noqa: ARG002
        return {
            "python_control": CNumberInput(
                name="threshold",
                value=Decimal("2.5"),
                min=Decimal(0),
                max=Decimal(10),
                step=Decimal("0.5"),
                input_attrs={"aria-label": "Python threshold"},
            )
        }

    template = """
      <section class="number-input-demo-grid">
        <c-CField required>
          <c-fill name="label">Crates</c-fill>
          <c-fill name="description">Choose from 1 through 20.</c-fill>
          <c-fill name="default">
            <c-CNumberInput name="crates" value="2" min="1" max="20" />
          </c-fill>
        </c-CField>
        <article><h3>Python composition</h3>{{ python_control }}</article>
      </section>
    """

    css = """
      :where(.number-input-demo-grid) {
        display:grid;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));gap:1rem;align-items:start
      }
      :where(.number-input-demo-grid article) { display:grid;gap:.75rem }
      :where(.number-input-demo-grid h3) { margin:0 }
    """


preview = BasicNumberInput()
preview  # noqa: B018

Standalone use needs an accessible name in input_attrs.

Keep decimals exact

Server inputs accept int, Decimal, or a plain-decimal string. Floats, scientific notation, NaN, and infinity are rejected. Client value is a canonical string or null.

Step exact fractional values
Show code
from citry import Component


class ExactDecimalNumberInput(Component):
    template = """
      <section class="number-input-example-stack">
        <c-CField>
          <c-fill name="label">Calibration offset</c-fill>
          <c-fill name="description">Exact increments of 0.0001.</c-fill>
          <c-fill name="default">
            <c-CNumberInput name="offset" value="0.1001" min="-1" max="1" step="0.0001" />
          </c-fill>
        </c-CField>
        <p>The submitted enhanced value remains the exact string <code>0.1001</code>.</p>
      </section>
    """
    css = ":where(.number-input-example-stack){display:grid;gap:.75rem;max-inline-size:28rem}"


preview = ExactDecimalNumberInput()
preview  # noqa: B018

step sets an exact grid based on min, or zero when min is omitted. Arrow keys move one step, Page Up and Page Down move ten, and Home/End use a supplied minimum/maximum. The adjacent Buttons do not add Tab stops.

Validate or clamp a committed draft

The default commit_behavior="validate" leaves an out-of-range or off-grid draft visible and invalid. Set commit_behavior="clamp" to clamp a parse-valid out-of-range draft on blur or Enter. Clamp never guesses an incomplete or malformed value.

Compare validation and clamping
Show code
from citry import Component


class NumberInputConstraints(Component):
    template = """
      <section class="number-input-example-grid">
        <c-CField required>
          <c-fill name="label">Validate the draft</c-fill>
          <c-fill name="description">Enter a quarter step from 0 through 3.</c-fill>
          <c-fill name="default"><c-CNumberInput value="1" min="0" max="3" step="0.25" /></c-fill>
        </c-CField>
        <c-CField>
          <c-fill name="label">Clamp on commit</c-fill>
          <c-fill name="description">A parse-valid outside value moves to the nearest bound.</c-fill>
          <c-fill name="default"><c-CNumberInput value="1" min="0" max="3" commit_behavior="clamp" /></c-fill>
        </c-CField>
      </section>
    """
    css = """
      :where(.number-input-example-grid) {
        display:grid;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));gap:1rem
      }
    """


preview = NumberInputConstraints()
preview  # noqa: B018

invalid=True combines application validation with required, parse, minimum, maximum, and step validity. Inside Field, set required, disabled, readonly, and invalid on Field rather than on NumberInput.

Control the canonical value

Pass client value and onValueChange through $c-props. A controlled interaction is a request: the displayed committed value and Form transport do not change until the owner supplies the requested exact string.

Control exact value ownership
Show code
from citry import Component


class ControlledNumberInput(Component):
    template = """
      <section x-data="{value:'2',last:'No request yet'}" class="number-input-example-stack">
        <c-CNumberInput
          c-input_attrs="{'aria-label':'Controlled quantity'}"
          $c-props="{
            value,
            onValueChange:(next,detail)=>{value=next;last=`${detail.source}: ${next}`},
          }"
        />
        <output x-text="`Canonical value: ${value}; ${last}`">Canonical value: 2</output>
      </section>
    """
    css = ":where(.number-input-example-stack){display:grid;gap:.75rem;max-inline-size:28rem}"


preview = ControlledNumberInput()
preview  # noqa: B018

onInputValueChange reports the literal draft and its empty, incomplete, invalid, or valid parse status. It does not make the draft a second controlled axis. Native @input also remains available through input_attrs.

Hide controls or enable wheel stepping

Set show_controls=False for a text-only spinbutton. Keyboard stepping remains available. Mouse-wheel and trackpad stepping are disabled by default so page scrolling cannot accidentally change a value; opt in with wheel=True.

Use a compact text-only spinbutton
Show code
from citry import Component


class NumberInputWithoutControls(Component):
    template = """
      <c-CField>
        <c-fill name="label">Keyboard stepper</c-fill>
        <c-fill name="description">Use Arrow Up/Down; adjacent controls are hidden.</c-fill>
        <c-fill name="default">
          <c-CNumberInput value="5" min="0" max="10" c-show_controls="False" />
        </c-fill>
      </c-CField>
    """


preview = NumberInputWithoutControls()
preview  # noqa: B018
Opt in to focused wheel stepping
Show code
from citry import Component


class WheelNumberInput(Component):
    template = """
      <section class="number-input-example-grid">
        <c-CField>
          <c-fill name="label">Wheel remains page scrolling</c-fill>
          <c-fill name="default"><c-CNumberInput value="4" /></c-fill>
        </c-CField>
        <c-CField>
          <c-fill name="label">Focused wheel changes value</c-fill>
          <c-fill name="description">Explicitly enabled for this control.</c-fill>
          <c-fill name="default"><c-CNumberInput value="4" wheel /></c-fill>
        </c-CField>
      </section>
    """
    css = """
      :where(.number-input-example-grid) {
        display:grid;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));gap:1rem
      }
    """


preview = WheelNumberInput()
preview  # noqa: B018

Use localized decimal editing

With configured Citry i18n, the server formats the initial value through the citry-ui-number-input number profile. Under a client-enabled <c-i18n> provider, the editor accepts that locale's digits, decimal separator, grouping, and signs and reformats an idle value after a live locale change.

Inspect locale-aware NumberInput composition
Show code
from citry import Component


class LocalizedNumberInput(Component):
    template = """
      <section class="number-input-example-stack">
        <p>
          Place the same component under a client-enabled
          <code>&lt;c-i18n&gt;</code> provider to switch locale in place.
        </p>
        <c-CNumberInput
          value="1234.5"
          step="0.1"
          c-input_attrs="{'aria-label':'Localized measurement'}"
        />
        <p>
          The editor and its ARIA value text use the provider locale; the
          enhanced Form value stays <code>1234.5</code>.
        </p>
      </section>
    """
    css = ":where(.number-input-example-stack){display:grid;gap:.75rem;max-inline-size:32rem}"


preview = LocalizedNumberInput()
preview  # noqa: B018

Without i18n configuration, the exact source format is canonical ASCII. If a page uses server-only localized i18n, NumberInput keeps the localized SSR text until focus and then exposes the separately shipped canonical value; it never guesses which punctuation the server rendered.

An application may override every library-authored label or validity message. An explicit override stays fixed during locale switches and creates no catalog binding.

Preserve native Form behavior

Without JavaScript, the visible text input owns name and submits its literal localized value for server parsing. After enhancement, an owned hidden input submits the canonical decimal while the visible editor owns native validity.

Submit and reset canonical values
Show code
from citry import Component


class NumberInputForms(Component):
    template = """
      <form
        x-data="{submitted:'Not submitted'}"
        @submit.prevent="submitted=new FormData($event.target).get('amount')"
        class="number-input-example-stack"
      >
        <c-CField required>
          <c-fill name="label">Amount</c-fill>
          <c-fill name="default"><c-CNumberInput name="amount" value="1.25" step="0.25" /></c-fill>
        </c-CField>
        <div><button type="submit">Submit</button> <button type="reset">Reset</button></div>
        <output x-text="submitted">Not submitted</output>
      </form>
    """
    css = ":where(.number-input-example-stack){display:grid;gap:.75rem;max-inline-size:28rem}"


preview = NumberInputForms()
preview  # noqa: B018

Readonly values remain focusable and submit. Disabled values do not submit. An uncanceled reset restores the server value; controlled state receives a reset request.

Choose a variant, size, and public style

Outline, filled, and plain variants combine with sm, md, and lg sizes. Public --cui-number-input-* variables and [data-citry-ui-part="..."] selectors customize the stable root, control, editor, and step Buttons.

Compare NumberInput states and styling
Show code
from citry import Component


class NumberInputStates(Component):
    template = """
      <section class="number-input-state-grid">
        <c-CNumberInput value="2" variant="outline" size="sm" c-input_attrs="{'aria-label':'Small outline'}" />
        <c-CNumberInput value="2" variant="filled" size="md" c-input_attrs="{'aria-label':'Medium filled'}" />
        <c-CNumberInput value="2" variant="plain" size="lg" c-input_attrs="{'aria-label':'Large plain'}" />
        <c-CNumberInput value="2" readonly c-input_attrs="{'aria-label':'Readonly'}" />
        <c-CNumberInput value="2" disabled c-input_attrs="{'aria-label':'Disabled'}" />
        <c-CNumberInput value="2" invalid c-input_attrs="{'aria-label':'Application invalid'}" />
      </section>
    """
    css = """
      :where(.number-input-state-grid) {
        display:grid;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));gap:1rem;align-items:start
      }
    """


preview = NumberInputStates()
preview  # noqa: B018

Logical CSS supports RTL while plus and minus keep their mathematical meaning. Coarse pointers receive larger targets; forced colors preserve borders and focus; print hides the controls.

API reference

Inputs

CNumberInput server inputs

Server inputs are passed in a template through <c-CNumberInput ... /> or in Python through CNumberInput(...).

InputTypeDefaultEffect
valueCNumberInputExact | None (CNumberInputExact)NoneSets the initial exact canonical decimal or empty value.
namestr | NoneNoneSets the progressive native Form field name.
formstr | NoneNoneAssociates the visible fallback and enhanced transport with an external Form ID.
idstr | NonegeneratedSets the public editor ID and bases the private transport ID.
minCNumberInputExact | None (CNumberInputExact)NoneSets the inclusive exact minimum and step-grid base.
maxCNumberInputExact | None (CNumberInputExact)NoneSets the inclusive exact maximum.
stepCNumberInputExact (CNumberInputExact)1Sets a positive exact step.
requiredbool | NoneNoneEnables empty-value validity outside Field; Field owns it inside Field.
disabledbool | NoneNoneBlocks focus mutation and Form submission outside Field; Form disabledness also wins.
readonlybool | NoneNoneKeeps a focusable submitted value while blocking mutation.
invalidbool | NoneNoneAdds application invalid state to native component validity.
show_controlsboolTrueShows or hides adjacent decrement and increment Buttons.
wheelboolFalseOpts a focused editor into wheel and trackpad stepping.
commit_behavior"validate" | "clamp" (CNumberInputCommitBehavior)"validate"Leaves an invalid committed draft visible or clamps a parse-valid out-of-range value.
placeholderstr | NoneNoneSets ordinary editor placeholder text.
autocompletestr | NoneNoneSets the native autocomplete hint.
increment_labelstr"Increase value"Overrides the catalog-backed increment Button accessible name.
decrement_labelstr"Decrease value"Overrides the catalog-backed decrement Button accessible name.
required_messagestr"Enter a number."Overrides catalog-backed empty required validity.
invalid_messagestr"Enter a valid number."Overrides catalog-backed parse validity.
minimum_messagestr containing '{min}'"Enter a value of at least {min}."Overrides catalog-backed minimum validity.
maximum_messagestr containing '{max}'"Enter a value of at most {max}."Overrides catalog-backed maximum validity.
step_messagestr containing '{step}'"Enter a value in increments of {step}."Overrides catalog-backed step-grid validity.
variant"outline" | "filled" | "plain" (CNumberInputVariant)"outline"Selects visual treatment.
size"sm" | "md" | "lg" (CNumberInputSize)"md"Selects coordinated editor and control sizing.
class_CClassValue | None (CClassValue)NoneAdds classes to the documented root and merges with attrs.
styleCStyleValue | None (CStyleValue)NoneAdds styles to the documented root and merges with attrs.
attrsMapping[str, object] | NoneNoneAdds copied allowed root attributes without replacing owned state or runtime identity.
input_attrsMapping[str, object] | NoneNoneAdds copied allowed editor attributes including accessible naming and native event observers.

CNumberInput client inputs

Client inputs are passed in the browser through the $c-props="{ ... }" attribute on <c-CNumberInput />.

InputTypeOmitted behaviorEffect
valuecanonical string | nullReleases control to the last uncontrolled committed value.Controls the exact canonical value while supplied.
mincanonical string | nullUses the server minimum.Replaces or removes the inclusive minimum.
maxcanonical string | nullUses the server maximum.Replaces or removes the inclusive maximum.
steppositive canonical stringUses the server step.Replaces the exact step grid.
requiredbooleanUses server or Field state.Controls standalone required validity.
disabledbooleanUses server or owner state.Controls mutation and Form participation.
readonlybooleanUses server or owner state.Controls focusable nonmutable state.
invalidbooleanUses server or Field state.Controls application invalid state.
showControlsbooleanUses the server input.Controls adjacent Button visibility.
wheelbooleanUses the server input.Controls focused wheel stepping.
commitBehavior"validate" | "clamp" (CNumberInputCommitBehavior)Uses the server input.Controls out-of-range commit policy.
placeholderstring | nullUses the server input.Controls visible placeholder text.
autocompletestring | nullUses the server input.Controls the autocomplete hint.
variant"outline" | "filled" | "plain" (CNumberInputVariant)Uses the server input.Controls visual treatment.
size"sm" | "md" | "lg" (CNumberInputSize)Uses the server input.Controls coordinated sizing.
onValueChangefunctionNo semantic value callback.Receives successful commit and reset requests.
onInputValueChangefunctionNo semantic draft callback.Receives literal draft edits and parse status.

Slots

-

Events

Component events are callback inputs supplied through $c-props. Native browser events remain available through Alpine @... attributes.

CNumberInput events

EventSignatureTrigger and timingDetailControlled and cancellation behavior
onValueChange(value: string | null, detail: CNumberInputValueChangeDetail) => void (CNumberInputValueChangeDetail)A valid blur, Enter, step, bound jump, wheel step, or reset requests a changed canonical value.{value, previousValue, inputValue, controlled, source, sourceEvent} (CNumberInputValueChangeDetail)Uncontrolled state and canonical Form transport commit before notification; controlled state is request-only.
onInputValueChange(inputValue: string, detail: CNumberInputInputValueChangeDetail) => void (CNumberInputInputValueChangeDetail)A native input or completed IME composition changes the literal editor draft.{inputValue, previousInputValue, status, controlled, composing, sourceEvent} (CNumberInputInputValueChangeDetail)Reports the draft without committing or reformatting it; native input remains observable through input_attrs.

Methods

-

CSS

CSS variables to theme the components. Set them on an ancestor or the component itself.

CNumberInput CSS variables

Apply these variables to CNumberInput or one of its ancestors.

VariableTypePurposeDefault
--cui-number-input-backgroundcolorControl background.Canvas
--cui-number-input-foregroundcolorEditor and icon foreground.CanvasText
--cui-number-input-border-colorcolorControl and step-divider border.Mixed CanvasText.
--cui-number-input-focus-colorcolorFocus border and ring.Highlight
--cui-number-input-invalid-border-colorcolorInvalid border.Theme error.
--cui-number-input-radiuslengthControl corner radius.0.5rem
--cui-number-input-heightlengthEditor and Button height.2.5rem
--cui-number-input-inline-paddinglengthEditor inline inset.0.75rem
--cui-number-input-control-sizelengthStep Button inline size.2.5rem

Attributes

HTML attributes defined on the components that you can refer to for CSS, inspection, and testing. Read-only.

CNumberInput attributes

AttributeElementTypeMeaning
data-emptyRoot divpresent | absentMirrors an empty canonical value.
data-requiredRoot divpresent | absentMirrors effective requiredness.
data-disabledRoot divpresent | absentMirrors effective disabledness.
data-readonlyRoot divpresent | absentMirrors effective readonly state.
data-invalidRoot divpresent | absentMirrors application or revealed component invalidity.
data-variantRoot divCNumberInputVariant (CNumberInputVariant)Mirrors visual treatment.
data-sizeRoot divCNumberInputSize (CNumberInputSize)Mirrors coordinated sizing.

CNumberInput attributes

AttributeElementTypeMeaning
roleEditor input"spinbutton"Exposes numeric stepping semantics while preserving text editing.
inputmodeEditor input"decimal"Requests a decimal-capable virtual keyboard.
aria-valuenowEditor inputcanonical decimal | absentExposes a valid committed canonical value.
aria-valuetextEditor inputlocalized string | absentExposes the locale-formatted committed value.
aria-valueminEditor inputcanonical decimal | absentExposes the inclusive minimum.
aria-valuemaxEditor inputcanonical decimal | absentExposes the inclusive maximum.
aria-invalidEditor input"true" | absentMirrors application or revealed native validity.

CNumberInput attributes

AttributeElementTypeMeaning
typeStep Buttons"button"Prevents accidental Form submission.
tabindexStep Buttons"-1"Keeps the editor as the sole sequential Tab stop.
aria-labelStep Buttonslocalized stringNames increment or decrement.

Selectors

Selectors for the DOM nodes in the components that you can use for CSS, inspection, and testing.

CNumberInput selectors

SelectorElementPurpose
[data-citry-ui-part="number-input"]Root divState reflections and class_, style, and attrs destination.
[data-citry-ui-part="control"]Control divContains the editor and optional step Buttons.
[data-citry-ui-part="input"]Text inputPublic focus target and input_attrs destination.
[data-citry-ui-part="decrement"]ButtonRequests one exact decrement.
[data-citry-ui-part="increment"]ButtonRequests one exact increment.

Interfaces

Aliases and data shapes referenced above.

Input type aliases

InterfaceDefinition
CNumberInputExactint | Decimal | str
CNumberInputCommitBehaviorLiteral["validate", "clamp"]
CNumberInputVariantLiteral["outline", "filled", "plain"]
CNumberInputSizeLiteral["sm", "md", "lg"]
CNumberInputParseStatusLiteral["empty", "incomplete", "invalid", "valid"]
CNumberInputChangeSourceLiteral["blur", "enter", "increment", "decrement", "page", "home", "end", "wheel", "reset"]
CClassValuestr | Mapping[str, bool] | Sequence[CClassValue]
CStyleValuestr | Mapping[str, object] | Sequence[CStyleValue]

CNumberInputValueChangeDetail

FieldTypeDefaultMeaning
valuestring | null-Requested exact canonical value.
previousValuestring | null-Effective canonical value before the request.
inputValuestring-Visible formatted text associated with the request.
controlledboolean-Whether client value owns canonical state.
sourceCNumberInputChangeSource (CNumberInputChangeSource)-Interaction or reset cause.
sourceEventobject | null-Native interaction event when one exists.

CNumberInputInputValueChangeDetail

FieldTypeDefaultMeaning
inputValuestring-Current literal draft.
previousInputValuestring-Literal draft before this native input.
statusCNumberInputParseStatus (CNumberInputParseStatus)-Locale-aware parse state.
controlledboolean-Whether client value owns canonical state.
composingboolean-Whether an input method composition remains active.
sourceEventobject | null-Native input or composition event.

Translation keys

Catalog keys used by this family. An explicit component input or slot listed in Override takes precedence over the catalog for that instance.

CNumberInput translation keys

KeyPurposeVariablesOverrideBrowser updates
citry-ui-number-input-decrementNames the decrement Button.Nonedecrement_label$c-tr updates the stable aria-label.
citry-ui-number-input-incrementNames the increment Button.Noneincrement_label$c-tr updates the stable aria-label.
citry-ui-number-input-requiredSupplies empty required validity.Nonerequired_messageActive i18n.bind() custom-validity destination.
citry-ui-number-input-invalidSupplies malformed or incomplete draft validity.Noneinvalid_messageActive i18n.bind() custom-validity destination.
citry-ui-number-input-minimumSupplies inclusive-minimum validity.min: strminimum_messagei18n.bind() with locale-formatted min.
citry-ui-number-input-maximumSupplies inclusive-maximum validity.max: strmaximum_messagei18n.bind() with locale-formatted max.
citry-ui-number-input-stepSupplies exact step-grid validity.step: strstep_messagei18n.bind() with locale-formatted step.