gr.Number — the text field that promises you a number

Bounds and precision live on the component; None means empty, 0 means zero.

The frontend turns an empty gr.Number into 0 before your function ever sees it — if your model treats 0 and 'no value' differently, you're already bitten.

What it does

gr.Number renders a native HTML <input type="number"> — the browser gives you spinner arrows for free. Your fn receives a float or int (with precision=0), or None when the field is empty. minimum/maximum are enforced server-side in preprocess(); step feeds the browser spinner; placeholder shows on the empty field.

Why it matters

It's the input for every demo with a knob that isn't a slider: temperature, threshold, count, salary. Unlike gr.Slider it doesn't imply a range — you get unbounded input with optional rails, so users can type 1,000,000 without you drawing a track to match. And every gr.Number is simultaneously a REST parameter: gradio_client sends it as JSON in the event body.

Examples

import gradio as gr

def double(x):
    return None if x is None else x * 2

with gr.Blocks(title="Doubling Machine") as demo:
    with gr.Row():
        num = gr.Number(label="amount", info="Any number, doubled.")
        btn = gr.Button("Double")
    out = gr.Number(label="doubled")
    btn.click(double, inputs=num, outputs=out)

demo.launch(prevent_thread_lock=True)
* Running on local URL:  http://127.0.0.1:7860
* To create a public link, set `share=True` in `launch()`.

Rendered UI (verified via /config on 6.28.0):
- a Row holding Number "amount" (info text "Any number, doubled.") and Button "Double"
- below: Number "doubled"
Event listener: targets=[[4,'click']], api_name="/double"
End-to-end API call: POST /gradio_api/call/double with [7] streams back event: complete, data: [14]

Verified on gradio 6.28.0 (Python 3.12) by launching and calling the event API. Note the None guard: with an empty field the frontend coerces value to 0 — but the API path sends null, which arrives as None. Handle both.

import gradio as gr

def tax(gross, rate):
    return round(gross * rate / 100, 2)

demo = gr.Interface(
    fn=tax,
    inputs=[
        gr.Number(label="Gross salary", precision=0, value=48000),
        gr.Number(label="Tax rate %", minimum=0, maximum=100, step=0.5, value=23.5),
    ],
    outputs=gr.Number(label="Tax owed", precision=2),
    title="Salary Tax Estimator",
)
demo.launch(prevent_thread_lock=True)
* Running on local URL:  http://127.0.0.1:7860

Rendered UI (verified via /config on 6.28.0):
- centered title "Salary Tax Estimator"
- left column: Number "Gross salary" (value 48000, precision 0) and Number "Tax rate %" (min 0, max 100, step 0.5, value 23.5)
- Clear and Submit buttons
- right column: Number "Tax owed" (precision 2), below it a Flag button
Event listener: targets=[[19,'click'],[8,'submit'],[9,'submit']], api_name="/tax"
Call /tax [48000, 23.5] -> event: complete, data: [11280.0]
Call /tax [48000, 150] -> event: error, data: {"error": "Value 150 is greater than maximum value 100.", ...}

Verified on 6.28.0 including the out-of-bounds rejection — the Error is raised in preprocess() before tax() runs, and the queue streams it back as an event: error frame. precision=0 sends your fn an int (48000, not 48000.0).

import gradio as gr

with gr.Blocks(title="Live Ticker") as demo:
    timer = gr.Timer(1.5)
    readout = gr.Number(label="seconds since load", every=timer, interactive=False)
    counter = gr.Number(label="tick count", value=0)
    timer.tick(lambda c: c + 1, inputs=[counter], outputs=counter)

demo.launch(prevent_thread_lock=True)
* Running on local URL:  http://127.0.0.1:7860

Rendered UI (verified via /config on 6.28.0):
- component types: ['timer', 'number', 'number', 'form']
- Timer(1.5) driving Number "seconds since load" via every=, plus Number "tick count" driven by timer.tick
Event listener: targets=[[1,'tick']], api_name="/lambda"

Verified on 6.28.0. every= turns a read-only Number into a live readout: the frontend re-runs your fn every 1.5 s and updates the field without any user action. The same every= accepts a float of seconds on older versions; Timer objects are the current idiom.

# what preprocess() actually does to your payload
import gradio as gr
from gradio.components.number import Number

n = Number(precision=0)
print(n.round_to_precision(3.7, 0))    # int(round(3.7))
n2 = Number(precision=2)
print(n2.postprocess(2.71828))         # rounded for display

nb = Number(minimum=0, maximum=100)
nb.preprocess(150)                     # raises before fn runs
4
2.72
gradio.exceptions.Error: 'Value 150 is greater than maximum value 100.'

Rounding semantics verified on 6.28.0 (round_to_precision is Python's round(), i.e. banker's rounding):
0.5 -> 0, 1.5 -> 2, 2.5 -> 2, 3.5 -> 4
preprocess(None) -> None (no bounds check, no rounding)
preprocess(3.777) with precision=None -> 3.777 untouched

Verified by calling the real methods on 6.28.0. precision=0 returns int(round(x)); precision=None passes the float through untouched; None payloads bypass everything — bounds are never checked on empty fields.

Flags

FlagMeaning
value=NoneEmpty field shows the placeholder if set, otherwise the browser shows 0 — but the payload to your fn is None on the API path.
precisionNone keeps floats untouched; 0 returns int(round(x)); 2 rounds to 2 decimals — applies to inputs AND outputs.
minimum / maximumOptional rails, enforced in preprocess() — out-of-range calls fail with a visible Error before your fn runs.
stepFeeds the browser's native spinner and keyboard arrows (default 1); set 0.5 for half-steps.
every=gr.Timer(1.5)Re-runs the bound fn on a timer and updates the field — the live-readout idiom (also accepts a float of seconds).
infoHelper text under the label — the cheapest place to document units ('USD', '°C', '0–1').
placeholderGhost text on the empty field; since 5.35.0 (PR #11429) — use it to hint at format, not to teach.

It started as a flag, not a component (2019–2021)

gradio 0.1.0 (Feb 19, 2019) had no Number class — only 8 input components in a 1k-line inputs.py. In gradio 1.0.0 (Jul 2020), "number" was a string shortcut that set {"numeric": True} on a Textbox. The real Number(InputComponent) class with the "number" shortcut appears in gradio 2.0.0 (May 2021), when the component split into inputs.py/outputs.py.

Rails arrived late (2023–2025)

minimum/maximum landed in 3.35.0 (Jun 2023, PR #3991), step in 3.40.0 (Aug 2023, PR #5047), and precision dates to 3.4.1 (Oct 2022, PR #1125 — backend-only at first). The .blur event was only added in 5.32.0 (May 2025, PR #11262), a decade into the project's life. The famous "0 is ignored" bug (#10369) was fixed in 5.13.0 (Jan 2025).

Under the hood: two conversions and a DOM truth

preprocess(payload) checks bounds (raising gradio.exceptions.Error with 'Value 150 is greater than maximum value 100.'), then applies round_to_precision(x, precision) — a None payload passes through untouched. postprocess() rounds your return value the same way before it reaches the browser. The compiled Svelte (Index-D-D2RBBM.js in 6.28.0) reveals the contract: a native <input type="number"> that coerces a null value to 0, dispatches input on every keystroke, submit on Enter keypress (preventDefault included), and blur/focus on those DOM events. Validation errors surface as a .validation-error class on the field.

Fun facts

Pros

Cons

Takeaways