InputNumber

NumberFieldGitLab
Um input para valores numéricos com intervalo personalizável.

Uso

Use a diretiva v-model para controlar o valor do InputNumber.

<script setup lang="ts">
const value = ref(5)
</script>

<template>
  <NInputNumber v-model="value" />
</template>
<script setup lang="ts">
import { ref } from 'vue'

const value = ref(5)
</script>

<template>
  <NInputNumber v-model="value" />
</template>

Use a prop default-value para definir o valor inicial quando você não precisa controlar o estado.

<template>
  <NInputNumber :default-value="5" />
</template>
Este componente depende do pacote @internationalized/number, que fornece utilitários para formatar e interpretar números entre locales e sistemas de numeração.

Mín / Máx

Use as props min e max para definir os valores mínimo e máximo do InputNumber.

<script setup lang="ts">
const value = ref(5)
</script>

<template>
  <NInputNumber v-model="value" :min="0" :max="10" />
</template>
<script setup lang="ts">
import { ref } from 'vue'

const value = ref(5)
</script>

<template>
  <NInputNumber v-model="value" :min="0" :max="10" />
</template>

Etapa

Use a prop step para definir o valor do passo do InputNumber.

<script setup lang="ts">
const value = ref(5)
</script>

<template>
  <NInputNumber v-model="value" :step="2" />
</template>
<script setup lang="ts">
import { ref } from 'vue'

const value = ref(5)
</script>

<template>
  <NInputNumber v-model="value" :step="2" />
</template>

Orientação

Use a prop orientation para alterar a orientação do InputNumber.

<script setup lang="ts">
const value = ref(5)
</script>

<template>
  <NInputNumber v-model="value" orientation="vertical" />
</template>
<script setup lang="ts">
import { ref } from 'vue'

const value = ref(5)
</script>

<template>
  <NInputNumber v-model="value" orientation="vertical" />
</template>

Placeholder

Use a prop placeholder para definir um texto de placeholder.

<template>
  <NInputNumber placeholder="Enter a number" />
</template>

Cor

Use a prop color para alterar a cor do ring quando o InputNumber está em foco.

<script setup lang="ts">
const value = ref(5)
</script>

<template>
  <NInputNumber v-model="value" color="neutral" highlight />
</template>
<script setup lang="ts">
import { ref } from 'vue'

const value = ref(5)
</script>

<template>
  <NInputNumber v-model="value" color="neutral" highlight />
</template>

Variante

Use a prop variant para alterar a variante do InputNumber.

<script setup lang="ts">
const value = ref(5)
</script>

<template>
  <NInputNumber v-model="value" variant="subtle" color="neutral" />
</template>
<script setup lang="ts">
import { ref } from 'vue'

const value = ref(5)
</script>

<template>
  <NInputNumber v-model="value" variant="subtle" color="neutral" />
</template>

Tamanho

Use a prop size para alterar o tamanho do InputNumber.

<script setup lang="ts">
const value = ref(5)
</script>

<template>
  <NInputNumber v-model="value" size="xl" />
</template>
<script setup lang="ts">
import { ref } from 'vue'

const value = ref(5)
</script>

<template>
  <NInputNumber v-model="value" size="xl" />
</template>

Desabilitado

Use a prop disabled para desabilitar o InputNumber.

<script setup lang="ts">
const value = ref(5)
</script>

<template>
  <NInputNumber v-model="value" disabled />
</template>
<script setup lang="ts">
import { ref } from 'vue'

const value = ref(5)
</script>

<template>
  <NInputNumber v-model="value" disabled />
</template>

Incrementar / Decrementar

Use as props increment e decrement para personalizar os botões de incremento e decremento com quaisquer props do Button. O padrão é { variant: 'link' }.

<script setup lang="ts">
const value = ref(5)
</script>

<template>
  <NInputNumber
    v-model="value"
    :increment="{
      color: 'neutral',
      variant: 'solid',
      size: 'xs'
    }"
    :decrement="{
      color: 'neutral',
      variant: 'solid',
      size: 'xs'
    }"
  />
</template>
<script setup lang="ts">
import { ref } from 'vue'

const value = ref(5)
</script>

<template>
  <NInputNumber
    v-model="value"
    :increment="{
      color: 'neutral',
      variant: 'solid',
      size: 'xs'
    }"
    :decrement="{
      color: 'neutral',
      variant: 'solid',
      size: 'xs'
    }"
  />
</template>

Ícones de incrementar / decrementar

Use as props increment-icon e decrement-icon para personalizar o Icon dos botões. O padrão é i-lucide-plus / i-lucide-minus.

<script setup lang="ts">
const value = ref(5)
</script>

<template>
  <NInputNumber
    v-model="value"
    increment-icon="i-lucide-arrow-right"
    decrement-icon="i-lucide-arrow-left"
  />
</template>
<script setup lang="ts">
import { ref } from 'vue'

const value = ref(5)
</script>

<template>
  <NInputNumber
    v-model="value"
    increment-icon="i-lucide-arrow-right"
    decrement-icon="i-lucide-arrow-left"
  />
</template>

Exemplos

Com formato decimal

Use a prop format-options para personalizar o formato do valor.

Com formato de porcentagem

Use a prop format-options com style: 'percent' para personalizar o formato do valor.

Com formato de moeda

Use a prop format-options com style: 'currency' para personalizar o formato do valor.

Sem botões

Você pode usar as props increment e decrement para controlar a visibilidade dos botões.

Dentro de um FormField

Você pode usar o InputNumber dentro de um componente FormField para exibir um rótulo, texto de ajuda, indicador de obrigatório, etc.

Especifique o número de tentativas

Com slots

Use os slots #increment e #decrement para personalizar os botões.

API

Props

Prop Default Type
as'div'any

The element or component this component should render as.

placeholder string

The placeholder text when the input is empty.

color'primary' "primary" | "secondary" | "accent" | "success" | "info" | "warning" | "error" | "neutral"
variant'outline' "outline" | "soft" | "subtle" | "ghost" | "none"
size'md' "xs" | "sm" | "md" | "lg" | "xl"
highlightboolean

Highlight the ring color like a focus state.

fixedboolean

Keep the mobile text size on all breakpoints.

orientation'horizontal' "horizontal" | "vertical"

The orientation of the input number.

incrementtrueboolean | Omit<ButtonProps, LinkPropsKeys>

Configure the increment button. The color and size are inherited.

incrementIconappConfig.ui.icons.plusany

The icon displayed to increment the value.

incrementDisabledboolean

Disable the increment button.

decrementtrueboolean | Omit<ButtonProps, LinkPropsKeys>

Configure the decrement button. The color and size are inherited.

decrementIconappConfig.ui.icons.minusany

The icon displayed to decrement the value.

decrementDisabledboolean

Disable the decrement button.

autofocusboolean
autofocusDelay number
defaultValue NonNullable<T>
modelValue T | Mod extends { optional: true; } ? undefined : never
modelModifiers Mod
min number

The smallest value allowed for the input.

max number

The largest value allowed for the input.

step number

The amount that the input value changes with each increment or decrement "tick".

stepSnappingboolean

When false, prevents the value from snapping to the nearest increment of the step value

disabledboolean

When true, prevents the user from interacting with the Number Field.

requiredboolean

When true, indicates that the user must set the value before the owning form can be submitted.

id string

Id of the element

name string

The name of the field. Submitted with its owning form as part of a name/value pair.

formatOptions Intl.NumberFormatOptions

Formatting options for the value displayed in the number field. This also affects what characters are allowed to be typed by the user.

disableWheelChangeboolean

When true, prevents the value from changing on wheel scroll.

invertWheelChangeboolean

When true, inverts the direction of the wheel change.

readonlyboolean

When true, the Number Field is read-only.

focusOnChangeboolean

When true, the input will be focused when the value changes.

locale string

The locale to use for formatting and currencies

list string
autocomplete "on" | "off" | string & {}
ui { root?: SlotClass; base?: SlotClass; increment?: SlotClass; decrement?: SlotClass; }
Este componente também suporta todos os atributos HTML nativos de <input>.

Slots

Slot Type
increment{}
decrement{}

Emits

Event Type
update:modelValue[value: ApplyModifiers<T, Mod>]
blur[event: FocusEvent]
change[event: Event]

Expose

Ao acessar o componente por meio de um template ref, você pode usar o seguinte:

NameType
inputRefRef<HTMLInputElement | null>

Tema

app.config.ts
export default defineAppConfig({
  ui: {
    inputNumber: {
      slots: {
        root: 'relative inline-flex items-center',
        base: [
          'w-full rounded-md border-0 placeholder:text-dimmed disabled:cursor-not-allowed disabled:opacity-75',
          'transition-colors'
        ],
        increment: 'absolute flex items-center',
        decrement: 'absolute flex items-center'
      },
      variants: {
        fieldGroup: {
          horizontal: {
            root: 'group has-focus-visible:z-[1]',
            base: 'group-not-only:group-first:rounded-e-none group-not-only:group-last:rounded-s-none group-not-last:group-not-first:rounded-none'
          },
          vertical: {
            root: 'group has-focus-visible:z-[1]',
            base: 'group-not-only:group-first:rounded-b-none group-not-only:group-last:rounded-t-none group-not-last:group-not-first:rounded-none'
          }
        },
        color: {
          primary: '',
          secondary: '',
          accent: '',
          success: '',
          info: '',
          warning: '',
          error: '',
          neutral: ''
        },
        size: {
          xs: 'px-2 py-1 text-sm/4 gap-1',
          sm: 'px-2.5 py-1.5 text-sm/4 gap-1.5',
          md: 'px-2.5 py-1.5 text-base/5 gap-1.5',
          lg: 'px-3 py-2 text-base/5 gap-2',
          xl: 'px-3 py-2 text-base gap-2'
        },
        variant: {
          outline: 'text-highlighted bg-default ring ring-inset ring-accented',
          soft: 'text-highlighted bg-elevated/50 hover:bg-elevated focus:bg-elevated disabled:bg-elevated/50',
          subtle: 'text-highlighted bg-elevated ring ring-inset ring-accented',
          ghost: 'text-highlighted bg-transparent hover:bg-elevated focus:bg-elevated disabled:bg-transparent dark:disabled:bg-transparent',
          none: 'text-highlighted bg-transparent focus:outline-none'
        },
        disabled: {
          true: {
            increment: 'opacity-75 cursor-not-allowed',
            decrement: 'opacity-75 cursor-not-allowed'
          }
        },
        orientation: {
          horizontal: {
            base: 'text-center',
            increment: 'inset-y-0 end-0 pe-1',
            decrement: 'inset-y-0 start-0 ps-1'
          },
          vertical: {
            increment: 'top-0 end-0 pe-1 [&>button]:py-0 scale-80',
            decrement: 'bottom-0 end-0 pe-1 [&>button]:py-0 scale-80'
          }
        },
        highlight: {
          true: ''
        },
        fixed: {
          false: ''
        },
        increment: {
          false: ''
        },
        decrement: {
          false: ''
        }
      },
      compoundVariants: [
        {
          color: 'primary',
          variant: [
            'outline',
            'subtle'
          ],
          class: 'outline-primary/25 focus-visible:outline-3 focus-visible:ring-primary'
        },
        {
          color: 'primary',
          variant: [
            'soft',
            'ghost'
          ],
          class: 'outline-primary/25 focus-visible:outline-3'
        },
        {
          color: 'primary',
          highlight: true,
          class: 'ring ring-inset ring-primary'
        },
        {
          color: 'neutral',
          variant: [
            'outline',
            'subtle'
          ],
          class: 'outline-inverted/25 focus-visible:outline-3 focus-visible:ring-inverted'
        },
        {
          color: 'neutral',
          variant: [
            'soft',
            'ghost'
          ],
          class: 'outline-inverted/25 focus-visible:outline-3'
        },
        {
          color: 'neutral',
          highlight: true,
          class: 'ring ring-inset ring-inverted'
        },
        {
          orientation: 'horizontal',
          decrement: false,
          class: 'text-start'
        },
        {
          decrement: true,
          size: 'xs',
          class: 'ps-7'
        },
        {
          decrement: true,
          size: 'sm',
          class: 'ps-8'
        },
        {
          decrement: true,
          size: 'md',
          class: 'ps-9'
        },
        {
          decrement: true,
          size: 'lg',
          class: 'ps-10'
        },
        {
          decrement: true,
          size: 'xl',
          class: 'ps-11'
        },
        {
          increment: true,
          size: 'xs',
          class: 'pe-7'
        },
        {
          increment: true,
          size: 'sm',
          class: 'pe-8'
        },
        {
          increment: true,
          size: 'md',
          class: 'pe-9'
        },
        {
          increment: true,
          size: 'lg',
          class: 'pe-10'
        },
        {
          increment: true,
          size: 'xl',
          class: 'pe-11'
        },
        {
          fixed: false,
          size: 'xs',
          class: 'md:text-xs'
        },
        {
          fixed: false,
          size: 'sm',
          class: 'md:text-xs'
        },
        {
          fixed: false,
          size: 'md',
          class: 'md:text-sm'
        },
        {
          fixed: false,
          size: 'lg',
          class: 'md:text-sm'
        }
      ],
      defaultVariants: {
        size: 'md',
        color: 'primary',
        variant: 'outline'
      }
    }
  }
})
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nitro/ui/vite'

export default defineConfig({
  plugins: [
    vue(),
    ui({
      ui: {
        inputNumber: {
          slots: {
            root: 'relative inline-flex items-center',
            base: [
              'w-full rounded-md border-0 placeholder:text-dimmed disabled:cursor-not-allowed disabled:opacity-75',
              'transition-colors'
            ],
            increment: 'absolute flex items-center',
            decrement: 'absolute flex items-center'
          },
          variants: {
            fieldGroup: {
              horizontal: {
                root: 'group has-focus-visible:z-[1]',
                base: 'group-not-only:group-first:rounded-e-none group-not-only:group-last:rounded-s-none group-not-last:group-not-first:rounded-none'
              },
              vertical: {
                root: 'group has-focus-visible:z-[1]',
                base: 'group-not-only:group-first:rounded-b-none group-not-only:group-last:rounded-t-none group-not-last:group-not-first:rounded-none'
              }
            },
            color: {
              primary: '',
              secondary: '',
              accent: '',
              success: '',
              info: '',
              warning: '',
              error: '',
              neutral: ''
            },
            size: {
              xs: 'px-2 py-1 text-sm/4 gap-1',
              sm: 'px-2.5 py-1.5 text-sm/4 gap-1.5',
              md: 'px-2.5 py-1.5 text-base/5 gap-1.5',
              lg: 'px-3 py-2 text-base/5 gap-2',
              xl: 'px-3 py-2 text-base gap-2'
            },
            variant: {
              outline: 'text-highlighted bg-default ring ring-inset ring-accented',
              soft: 'text-highlighted bg-elevated/50 hover:bg-elevated focus:bg-elevated disabled:bg-elevated/50',
              subtle: 'text-highlighted bg-elevated ring ring-inset ring-accented',
              ghost: 'text-highlighted bg-transparent hover:bg-elevated focus:bg-elevated disabled:bg-transparent dark:disabled:bg-transparent',
              none: 'text-highlighted bg-transparent focus:outline-none'
            },
            disabled: {
              true: {
                increment: 'opacity-75 cursor-not-allowed',
                decrement: 'opacity-75 cursor-not-allowed'
              }
            },
            orientation: {
              horizontal: {
                base: 'text-center',
                increment: 'inset-y-0 end-0 pe-1',
                decrement: 'inset-y-0 start-0 ps-1'
              },
              vertical: {
                increment: 'top-0 end-0 pe-1 [&>button]:py-0 scale-80',
                decrement: 'bottom-0 end-0 pe-1 [&>button]:py-0 scale-80'
              }
            },
            highlight: {
              true: ''
            },
            fixed: {
              false: ''
            },
            increment: {
              false: ''
            },
            decrement: {
              false: ''
            }
          },
          compoundVariants: [
            {
              color: 'primary',
              variant: [
                'outline',
                'subtle'
              ],
              class: 'outline-primary/25 focus-visible:outline-3 focus-visible:ring-primary'
            },
            {
              color: 'primary',
              variant: [
                'soft',
                'ghost'
              ],
              class: 'outline-primary/25 focus-visible:outline-3'
            },
            {
              color: 'primary',
              highlight: true,
              class: 'ring ring-inset ring-primary'
            },
            {
              color: 'neutral',
              variant: [
                'outline',
                'subtle'
              ],
              class: 'outline-inverted/25 focus-visible:outline-3 focus-visible:ring-inverted'
            },
            {
              color: 'neutral',
              variant: [
                'soft',
                'ghost'
              ],
              class: 'outline-inverted/25 focus-visible:outline-3'
            },
            {
              color: 'neutral',
              highlight: true,
              class: 'ring ring-inset ring-inverted'
            },
            {
              orientation: 'horizontal',
              decrement: false,
              class: 'text-start'
            },
            {
              decrement: true,
              size: 'xs',
              class: 'ps-7'
            },
            {
              decrement: true,
              size: 'sm',
              class: 'ps-8'
            },
            {
              decrement: true,
              size: 'md',
              class: 'ps-9'
            },
            {
              decrement: true,
              size: 'lg',
              class: 'ps-10'
            },
            {
              decrement: true,
              size: 'xl',
              class: 'ps-11'
            },
            {
              increment: true,
              size: 'xs',
              class: 'pe-7'
            },
            {
              increment: true,
              size: 'sm',
              class: 'pe-8'
            },
            {
              increment: true,
              size: 'md',
              class: 'pe-9'
            },
            {
              increment: true,
              size: 'lg',
              class: 'pe-10'
            },
            {
              increment: true,
              size: 'xl',
              class: 'pe-11'
            },
            {
              fixed: false,
              size: 'xs',
              class: 'md:text-xs'
            },
            {
              fixed: false,
              size: 'sm',
              class: 'md:text-xs'
            },
            {
              fixed: false,
              size: 'md',
              class: 'md:text-sm'
            },
            {
              fixed: false,
              size: 'lg',
              class: 'md:text-sm'
            }
          ],
          defaultVariants: {
            size: 'md',
            color: 'primary',
            variant: 'outline'
          }
        }
      }
    })
  ]
})
Some colors in compoundVariants are omitted for readability. Check out the source code on GitLab.

Changelog

No recent changes