Stepper

A component used to input or adjust numbers, supporting custom steps, precision, formatting, and different layouts.

Component Features

  • 🔢 Numeric Control: Supports custom min, max, step, and precision values.
  • 🎨 Various Layouts: Control buttons can be placed on both sides, on the right, or configured to show buttons only.
  • 🔤 Formatting: Supports custom value formatting and parsing (e.g., currency format).
  • 📏 Multiple Sizes: Available in small, medium, and large sizes.
  • 🖱️ Long Press: Supports long-pressing buttons for continuous increment/decrement.
  • 📋 Form Integration: Integrates seamlessly with BrForm, supporting validation states.

Basic Usage

The most basic stepper, binding the value via v-model.

<script setup lang="ts">
import { ref } from 'vue'
import { BrStepper } from '@breezeui/vue'

const value = ref(1)
</script>

<template>
  <div class="flex items-center gap-4">
    <BrStepper v-model="value" />
    <span class="text-sm text-muted-foreground">Current Value: {{ value }}</span>
  </div>
</template>

Precision and Step

Use the step prop to set the step value and the precision prop to set decimal precision.

<script setup lang="ts">
import { ref } from 'vue'
import { BrStepper } from '@breezeui/vue'

const value = ref(0.5)
</script>

<template>
  <div class="flex items-center gap-4">
    <BrStepper v-model="value" :step="0.1" :precision="1" :min="0" :max="10" />
    <span class="text-sm text-muted-foreground">Current Value: {{ value }}</span>
  </div>
</template>

Formatting

You can customize how the value is displayed in the input using the formatter and parser props.

<script setup lang="ts">
import { ref } from 'vue'
import { BrStepper } from '@breezeui/vue'

const value = ref(1000)

const formatCurrency = (val: number | null) => {
  if (val === null) return ''
  return `$ ${val}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')
}

const parseCurrency = (val: string) => {
  return parseFloat(val.replace(/\$\s?|(,*)/g, ''))
}
</script>

<template>
  <BrStepper 
    v-model="value" 
    :step="100" 
    :formatter="formatCurrency" 
    :parser="parseCurrency" 
    class="w-48"
  />
</template>

Controls Position and Mode

Use controls-position to change the position of the buttons, and button-only to hide the input field and keep only the control buttons.

<script setup lang="ts">
import { ref } from 'vue'
import { BrStepper } from '@breezeui/vue'

const value1 = ref(1)
const value2 = ref(5)
</script>

<template>
  <div class="flex flex-col gap-6">
    <div class="space-y-2">
      <label class="text-sm font-medium">Controls on the right</label>
      <div>
        <BrStepper v-model="value1" controls-position="right" class="w-32" />
      </div>
    </div>
    
    <div class="space-y-2">
      <label class="text-sm font-medium">Buttons Only Mode</label>
      <div class="flex items-center gap-4">
        <BrStepper v-model="value2" button-only />
        <span class="font-mono text-lg w-8 text-center">{{ value2 }}</span>
      </div>
    </div>
  </div>
</template>

Size

Supports three different sizes: sm, md, and lg.

<script setup lang="ts">
import { ref } from 'vue'
import { BrStepper } from '@breezeui/vue'

const value1 = ref(1)
const value2 = ref(2)
const value3 = ref(3)
const value4 = ref(4)
const value5 = ref(5)
const value6 = ref(6)
</script>

<template>
  <div class="flex flex-col gap-4">
    <div class="flex items-center gap-4">
      <BrStepper v-model="value1" size="xs" />
      <span class="text-sm text-muted-foreground">xs (Extra Small Size)</span>
    </div>
    <div class="flex items-center gap-4">
      <BrStepper v-model="value2" size="sm" />
      <span class="text-sm text-muted-foreground">sm (Small Size)</span>
    </div>
    <div class="flex items-center gap-4">
      <BrStepper v-model="value3" size="md" />
      <span class="text-sm text-muted-foreground">md (Medium Size,Default)</span>
    </div>
    <div class="flex items-center gap-4">
      <BrStepper v-model="value4" size="lg" />
      <span class="text-sm text-muted-foreground">lg (Large Size)</span>
    </div>
    <div class="flex items-center gap-4">
      <BrStepper v-model="value5" size="xl" />
      <span class="text-sm text-muted-foreground">xl (Extra Large Size)</span>
    </div>
    <div class="flex items-center gap-4">
      <BrStepper v-model="value6" size="2xl" />
      <span class="text-sm text-muted-foreground">2xl (Massive Size)</span>
    </div>
  </div>
</template>

Form Integration

A typical application within forms, supporting validation states and disabled states in conjunction with BrFormItem.

<script setup lang="ts">
import { ref } from 'vue'
import { BrStepper, BrForm, BrFormItem, BrFormLabel, BrFormControl, BrFormMessage, BrButton, useToast } from '@breezeui/vue'

const formData = ref({
  amount: 5,
})

const rules = {
  amount: (value: any) => {
    if (!value) return 'Please enter quantity'
    if (value < 1 || value > 10) return 'Quantity must be between 1-10 between'
    return true
  }
}

const { toast } = useToast()

const onSubmit = (values: any) => {
  toast({
    title: 'Submit successful!',
    description: `Current quantity is: ${values.amount}`,
    variant: 'success'
  })
}

const onInvalidSubmit = () => {
  toast({
    title: 'Validation Failed',
    description: 'Please check if the form is filled out correctly',
    variant: 'error'
  })
}
</script>

<template>
  <div class="w-80">
    <BrForm 
      layout="vertical" 
      @submit="onSubmit"
      @invalid-submit="onInvalidSubmit"
    >
      <BrFormItem name="amount" :rules="rules.amount">
        <BrFormLabel>Purchase Quantity (Limits 1-10)</BrFormLabel>
        <BrFormControl>
          <BrStepper v-model="formData.amount" :min="0" :max="15" class="w-full" />
        </BrFormControl>
        <BrFormMessage />
      </BrFormItem>
      
      <BrFormItem name="disabled">
        <BrFormLabel>Disabled State</BrFormLabel>
        <BrFormControl>
          <BrStepper v-model="formData.amount" disabled class="w-full" />
        </BrFormControl>
      </BrFormItem>
      
      <BrButton type="submit" class="mt-4">
        Submit Validation
      </BrButton>
    </BrForm>
  </div>
</template>

Theme Customization

Combined with BrConfigProvider, you can globally override the component's default styles. Local styles can also be overridden via TailwindCSS.

<script setup lang="ts">
import { ref } from 'vue'
import { BrStepper, BrConfigProvider } from '@breezeui/vue'

const value = ref(1)

const themeConfig = {
  radius: 1, // Full rounding
  primary: '220 90% 56%',
}
</script>

<template>
  <BrConfigProvider :theme="themeConfig">
    <div class="space-y-4">
      <div class="space-y-2">
        <label class="text-sm font-medium">Use global config to change border radius</label>
        <div>
          <BrStepper v-model="value" />
        </div>
      </div>
      
      <div class="space-y-2">
        <label class="text-sm font-medium">Use TailwindCSS Local override style</label>
        <div>
          <BrStepper 
            v-model="value" 
            class="border-blue-500 rounded-full [&_button]:text-blue-600 [&_button:hover]:bg-blue-50" 
          />
        </div>
      </div>
    </div>
  </BrConfigProvider>
</template>

API Reference

BrStepper

PropTypeDefaultDescription
modelValue / v-modelnumber | null-Binding value
defaultValuenumber | null-Default value (uncontrolled mode)
minnumberNumber.MIN_SAFE_INTEGERMinimum value
maxnumberNumber.MAX_SAFE_INTEGERMaximum value
stepnumber1Step value for each change
precisionnumber-Numeric precision
disabledbooleanfalseWhether it is disabled
readonlybooleanfalseWhether it is readonly
size'sm' | 'md' | 'lg''md'Size of the stepper
formatter(value: number | null) => string-Format function for the input display
parser(value: string) => number | null-Parse function to extract number from input
debounceDelaynumber300Input debounce delay in ms
longPressbooleantrueEnable continuous changes via long press
buttonOnlybooleanfalseWhether to show buttons only (hide input)
controlsPosition'both' | 'right''both'Position of the control buttons
placeholderstring-Placeholder text

Events

Event NameDescriptionCallback Parameters
update:modelValueTriggered when the binding value changes(value: number | null)
changeTriggered when the binding value changes(value: number | null)
blurTriggered when the input loses focus(event: FocusEvent)
focusTriggered when the input gets focus(event: FocusEvent)