QuantitySelector
QuantitySelector allows the selection of a numeric value and the display of any additional information needed.
Basic usage
<template> <div class="inline-flex flex-col items-center"> <div class="flex border border-neutral-300 rounded-full bg-white"> <SfButton variant="tertiary" :disabled="count <= min" square class="rounded-r-none" :aria-controls="inputId" aria-label="Decrease value" @click="dec()" > <SfIconRemove /> </SfButton> <input :id="inputId" v-model="count" type="number" class="appearance-none mx-2 w-8 text-center bg-transparent font-medium [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-inner-spin-button]:display-none [&::-webkit-inner-spin-button]:m-0 [&::-webkit-outer-spin-button]:display-none [&::-webkit-outer-spin-button]:m-0 [-moz-appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none disabled:placeholder-disabled-900 focus-visible:outline focus-visible:outline-offset focus-visible:rounded-xs" :min="min" :max="max" @input="handleOnChange" /> <SfButton variant="tertiary" :disabled="count >= max" square class="rounded-l-none" :aria-controls="inputId" aria-label="Increase value" @click="inc()" > <SfIconAdd /> </SfButton> </div> <p class="text-xs mt-2 text-neutral-500"> <strong class="text-neutral-900">{{ max }}</strong> in stock </p> </div> </template> <script lang="ts" setup> import { ref, useId } from 'vue'; import { clamp } from '@storefront-ui/shared'; import { useCounter } from '@vueuse/core'; import { SfButton, SfIconAdd, SfIconRemove } from '@storefront-ui/vue'; const min = ref(1); const max = ref(10); const inputId = useId(); const { count, inc, dec, set } = useCounter(1, { min: min.value, max: max.value }); function handleOnChange(event: Event) { const currentValue = (event.target as HTMLInputElement)?.value; const nextValue = parseFloat(currentValue); set(clamp(nextValue, min.value, max.value)); } </script> With rounded buttons
<template> <div class="flex"> <SfButton square class="!rounded-full" :disabled="count <= min" :aria-controls="inputId" aria-label="Decrease value" @click="dec()" > <SfIconRemove /> </SfButton> <input :id="inputId" v-model="count" type="number" class="appearance-none px-2 mx-2 w-12 text-center bg-transparent font-medium [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-inner-spin-button]:display-none [&::-webkit-inner-spin-button]:m-0 [&::-webkit-outer-spin-button]:display-none [&::-webkit-outer-spin-button]:m-0 [-moz-appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none disabled:placeholder-disabled-900 focus-visible:outline focus-visible:outline-offset focus-visible:rounded-xs" :min="min" :max="max" @input="handleOnChange" /> <SfButton square class="!rounded-full" :disabled="count >= max" :aria-controls="inputId" aria-label="Increase value" @click="inc()" > <SfIconAdd /> </SfButton> </div> </template> <script lang="ts" setup> import { ref, useId } from 'vue'; import { useCounter } from '@vueuse/core'; import { SfButton, SfIconAdd, SfIconRemove } from '@storefront-ui/vue'; import { clamp } from '@storefront-ui/shared'; const min = ref(1); const max = ref(10); const inputId = useId(); const { count, inc, dec, set } = useCounter(1, { min: min.value, max: max.value }); function handleOnChange(event: Event) { const currentValue = (event.target as HTMLInputElement)?.value; const nextValue = parseFloat(currentValue); set(Number(clamp(nextValue, min.value, max.value))); } </script> Out of stock
<template> <div class="inline-flex flex-col items-center"> <div class="flex rounded-full border border-disabled-200 bg-disabled-100"> <SfButton variant="tertiary" square disabled :aria-controls="inputId" aria-label="Decrease value"> <SfIconRemove /> </SfButton> <input :id="inputId" type="number" disabled class="appearance-none mx-2 w-8 text-center bg-transparent font-medium [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-inner-spin-button]:display-none [&::-webkit-inner-spin-button]:m-0 [&::-webkit-outer-spin-button]:display-none [&::-webkit-outer-spin-button]:m-0 [-moz-appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none disabled:placeholder-disabled-900 focus-visible:outline focus-visible:outline-offset focus-visible:rounded-xs" placeholder="-" :min="min" :max="max" /> <SfButton variant="tertiary" square disabled :aria-controls="inputId" aria-label="Increase value"> <SfIconAdd /> </SfButton> </div> <p class="text-negative-700 font-medium text-xs mt-2">Out of stock</p> </div> </template> <script lang="ts" setup> import { ref, useId } from 'vue'; import { SfButton, SfIconAdd, SfIconRemove } from '@storefront-ui/vue'; const min = ref(1); const max = ref(10); const inputId = useId(); </script>