ข้ามไปเนื้อหา
WhereUI

ค้นหาในเอกสาร

ค้นหาชื่อ component หรือหน้าเอกสาร

NumberInput

WhereUI

ช่องกรอกตัวเลขพร้อมปุ่มเพิ่ม/ลด พิมพ์ค่าเองได้ กดลูกศรขึ้นลงได้ และกดค้างที่ปุ่มเพื่อเพิ่ม/ลดต่อเนื่อง

ลา 3 วันทำการ

ติดตั้ง

Terminal
pnpm dlx shadcn@latest add @whereui/number-input

ต้องผูก registry และติดตั้ง @whereui/theme นำหน้าเสมอเมื่อติดตั้งครั้งแรก

การใช้งาน

import { NumberInput } from "@/components/ui/number-input"const [days, setDays] = React.useState<number | null>(null)<NumberInput value={days} onChange={setDays} min={0} max={30} />

ตัวอย่างเพิ่มเติม

จำกัดค่าและสถานะปิดใช้งาน
ชั่วโมงล่วงเวลา เพิ่มทีละ 0.5
ปิดใช้งาน

Props

proptypeค่าเริ่มต้นคำอธิบาย
valuenumber | null—ค่าตัวเลข (null = ว่าง)
onChange(value: number | null) => void—ส่งค่าตัวเลขหรือ null เมื่อว่าง
minnumber—ค่าต่ำสุด
maxnumber—ค่าสูงสุด
stepnumber1ระยะเพิ่ม/ลดของปุ่มและปุ่มลูกศร (กด Alt/Shift เพื่อย่อ/ขยายระยะได้)
disabledboolean—ปิดการใช้งาน
placeholderstring—ข้อความเมื่อว่าง

ข้อควรรู้

  • ตัวเลขแสดงคั่นหลักพันอัตโนมัติตามภาษาไทย เช่น 1,500
  • คีย์ลูกศรขึ้น-ลง เพิ่ม/ลดค่า Alt = ขั้นเล็ก Shift = ขั้นใหญ่

ซอร์สโค้ด

components/ui/number-input.tsx
"use client"import * as React from "react"import { NumberField } from "@base-ui/react/number-field"import { MinusIcon, PlusIcon } from "lucide-react"import { cn } from "cn"function NumberInput({  value,  onChange,  min,  max,  step = 1,  disabled,  placeholder,  className,  ...props}: Omit<React.ComponentProps<"input">, "value" | "onChange" | "size" | "type"> & {  /** ค่าตัวเลข (null = ว่าง) */  value?: number | null  onChange?: (value: number | null) => void  min?: number  max?: number  step?: number}) {  return (    <NumberField.Root      data-slot="number-input"      value={value ?? null}      onValueChange={(v) => onChange?.(v)}      min={min}      max={max}      step={step}      disabled={disabled}      locale="th-TH"      className={cn(        "flex h-8 w-full min-w-0 items-center rounded-lg border border-input bg-transparent transition-colors outline-none focus-within:border-ring focus-within:ring-3 focus-within:ring-ring/50 data-invalid:border-destructive data-invalid:ring-3 data-invalid:ring-destructive/20 disabled:cursor-not-allowed disabled:opacity-50 disabled:pointer-events-none md:text-sm dark:bg-input/30 dark:data-invalid:border-destructive/50 dark:data-invalid:ring-destructive/40",        className      )}    >      <NumberField.Group className="flex w-full min-w-0 items-center">        <NumberField.Decrement          type="button"          aria-label="ลดค่า"          className="flex size-7 shrink-0 cursor-pointer items-center justify-center rounded-lg text-muted-foreground outline-none select-none hover:bg-muted focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 [&_svg]:size-4 [&_svg]:pointer-events-none"        >          <MinusIcon aria-hidden="true" />        </NumberField.Decrement>        <NumberField.Input          placeholder={placeholder}          className="w-full min-w-0 bg-transparent py-1 text-center text-base outline-none placeholder:text-muted-foreground md:text-sm"          {...props}        />        <NumberField.Increment          type="button"          aria-label="เพิ่มค่า"          className="flex size-7 shrink-0 cursor-pointer items-center justify-center rounded-lg text-muted-foreground outline-none select-none hover:bg-muted focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 [&_svg]:size-4 [&_svg]:pointer-events-none"        >          <PlusIcon aria-hidden="true" />        </NumberField.Increment>      </NumberField.Group>    </NumberField.Root>  )}export { NumberInput }