icetalker/filament-stepper
A stepper component for Filament forms that turns long forms into guided, multi-step wizards. Define steps with labels, icons, and descriptions, then let users move forward and back through a progress indicator—ideal for onboarding, checkout, and settings flows.
icetalker/filament-stepper is a small, single-purpose form component: a numeric input with increment/decrement controls (a "stepper"), rendered with Filament's native form styling. It fills a real gap — Filament ships TextInput::make('qty')->numeric() but no built-in stepper — so reach for it when you need bounded, button-driven integer entry (quantities, seats, retries, page counts) instead of a free-text number field.
Minimal install:
composer require icetalker/filament-stepper
This is a form-component package rather than a full Filament plugin, so most installs need no ->plugin() registration in your panel provider. Confirm by checking the service provider in vendor/icetalker/filament-stepper/src/. If the package ships compiled assets (resources/dist), run:
php artisan filament:assets
php artisan optimize:clear
First use case — a quantity field on a resource form:
use Icetalker\FilamentStepper\Forms\Components\Stepper;
Stepper::make('quantity')
->label('Quantity')
->minValue(1)
->maxValue(50)
->step(1)
->default(1)
->required();
Where to look first, in order:
README.md in the vendor directory — the authoritative list of chainable methods; treat the method names below as the conventional Filament shape and verify against it.src/Forms/Components/Stepper.php — the fluent API and defaults (a 200-line file, fast to read end-to-end).resources/views/ — the Blade + Alpine markup, which tells you exactly which DOM attributes and CSS classes you can target.composer.json — the filament/filament constraint, so you know whether it targets Filament v3 or v4 before you build on it.Because the package is young (13 stars, last release April 2026), budget 20 minutes to read the source before wiring it into anything load-bearing. The surface area is tiny, so that investment is cheap.
Bounded counters in resource forms. The highest-value pattern is replacing a plain numeric TextInput where users otherwise type out-of-range values:
Stepper::make('seats')
->minValue(1)
->maxValue($this->record?->max_seats ?? 10)
->step(1)
->required()
->integer();
Reactive totals. Combine with Filament's live state so the stepper drives a computed read-only field:
Stepper::make('quantity')
->minValue(1)
->maxValue(99)
->live()
->afterStateUpdated(function (Set $set, Get $get, $state) {
$set('subtotal', (float) $state * (float) $get('unit_price'));
}),
TextInput::make('subtotal')->readOnly()->dehydrated(false),
Cast $state explicitly — Livewire hands you strings from the DOM, not ints.
Repeater line items. Steppers shine inside repeaters, where a spinner is faster to operate than a keyboard on touch devices:
Repeater::make('items')
->schema([
Select::make('product_id')->relationship('product', 'name')->required(),
Stepper::make('quantity')->minValue(1)->maxValue(20)->default(1),
])
->columns(2),
Wizards and multi-step forms. Since it's just a Field, it composes normally with Wizard::make([...]) and ->columnSpan(). Nothing special is required — this is the main argument for a component over a hand-rolled Blade partial.
Custom Livewire forms. It works outside resources too, wherever Filament\Forms\Concerns\InteractsWithForms is in play — settings pages, action modals (Action::make(...)->form([...])), and table filters.
Persistence discipline. Pair the component with a model cast ('quantity' => 'integer') or an explicit ->integer()/->numeric() rule on the field. Do not rely on the widget to enforce type; the buttons do, keyboard entry may not.
minValue, maxValue, step, integer) are almost certainly the Filament convention but may differ. Grep the class for public function and build against what's actually there rather than examples you find online.filament/filament constraint in composer.json against your panel's major version. Filament v4 changed asset and view conventions; a v3-only package will silently render unstyled or throw a ViewException. Pin the package version in composer.json so a patch release can't shift behavior under you.composer update, the fix is php artisan filament:assets && php artisan view:clear. This is the single most common false-bug report with small Filament component packages.->rules(['integer', 'min:1', 'max:50']) or a FormRequest — assume typed values can exceed the configured bounds.->step(0.01) invites floating-point drift (0.1 + 0.2); store cents as integers and divide in the accessor.$state arrives as a string on submit. (int) casts in afterStateUpdated and dehydrateStateUsing(fn ($state) => (int) $state) prevent "2" === 2 surprises in policies, comparisons, and JSON columns.wire:key; if it doesn't, wrap the field or set a stable ->key()/->id() per item.--gray-* tokens, spot-check the enabled/disabled button contrast — small packages often hardcode a shade.->extraAttributes(['class' => 'w-24']) and ->extraInputAttributes(...); both are standard Field methods and usually enough for width, alignment, and text-centering.Field: Stepper::macro('quantity', fn () => Stepper::make(...)->minValue(1)). Register it in a service provider's boot() and you get a project-wide house style without touching vendor code.x-data). php artisan filament:assets first, console second, source third.TextInput with a suffix action (or Filament's own upcoming component) is a one-file change rather than a rewrite.How can I help you explore Laravel packages today?