rias/statamic-button-box
A Statamic addon that provides a Button Box fieldtype for building groups of configurable call-to-action buttons in the control panel. Editors can add button labels, links, and styling options, then reuse the button set across pages and templates for consistent CTAs.
Install it like any Statamic addon — Composer only, no manual provider registration (Statamic discovers packages that declare extra.statamic in their composer.json):
composer require rias/statamic-button-box
php artisan optimize:clear
Confirm it loaded before you touch a blueprint:
php artisan about # addons are listed here in recent Statamic versions
php artisan statamic:stache:clear
Where to look first. For a small addon like this, the README is usually a stub — the real documentation is two files:
vendor/rias/statamic-button-box/src/Fieldtypes/*.php — tells you the fieldtype handle (probably button_box) and, more importantly, which config keys it reads (options, default, clearable, multiple, max_items, icon, color, …).vendor/rias/statamic-button-box/resources/js/components/fieldtypes/*.vue — tells you which of those keys actually change rendering in the CP. If a config key isn't referenced there, it does nothing.First use case: replace a select on a page blueprint with something a client can scan at a glance.
# resources/blueprints/collections/pages/page.yaml
sections:
main:
fields:
- handle: hero_layout
field:
type: button_box
display: Hero layout
instructions: Pick how the hero should look.
default: split
options:
split: Split
centered: Centered
full: Full bleed
Then branch in Antlers:
{{ if hero_layout == 'split' }}
{{ partial:heroes/split }}
{{ elseif hero_layout == 'centered' }}
{{ partial:heroes/centered }}
{{ elseif hero_layout == 'full' }}
{{ partial:heroes/full }}
{{ /if }}
That's the 90% case: the stored value is the option key, and your templates react to it exactly as they would to a select.
Always use the key→label map form. The key is what lands in the content file; the label is CP decoration only. Never store labels.
Pair it with conditional visibility so the choice drives the rest of the form:
- handle: hero_image
field:
type: assets
container: main
max_files: 1
if:
hero_layout: 'split' # or a `show_when`-style condition depending on your Statamic version
Human-readable output. The raw value is the key. If the fieldtype registers an augmentation/label method you can often do {{ hero_layout:label }}; verify in the CP by dumping the augmented value. If it doesn't, keep a mapping close to the template:
{{# resources/views/partials/layout-label.antlers.html #}}
{{ if hero_layout == 'split' }}Split
{{ elseif hero_layout == 'centered' }}Centered
{{ else }}Full bleed
{{ /if }}
…or expose a translated label from a config file and use {{ trans:layouts.hero_layout.split }}.
Share option sets across blueprints with a fieldset, so the option list exists once:
# resources/fieldsets/common/hero_layout.yaml
title: Hero layout
fields:
-
handle: hero_layout
field:
type: button_box
options:
split: Split
centered: Centered
full: Full bleed
# in the page blueprint
import:
- common/hero_layout
Inside Replicator / Grid / Bard sets. It works as a normal nested field, but resist it there: a button box inside a repeating set produces a wall of buttons. Keep button boxes for top-level, one-per-page decisions (layout, alignment, variant, theme), and use select inside repeaters.
Reading it in PHP / custom controllers:
$layout = $entry->get('hero_layout'); // 'split'
$label = $entry->augmentedValue('hero_layout'); // augmented value, if the fieldtype supports label()
Rendering in Blade passed through from a controller or view composer:
@switch($entry->get('hero_layout'))
@case('split') @include('heroes.split') @break
@case('centered') @include('heroes.centered') @break
@default @include('heroes.full')
@endswitch
Defaults matter. Set default: in the blueprint so new entries aren't null-valued and your {{ if }} chain has a guaranteed starting point.
composer require rias/statamic-button-box:^1.0), commit your composer.lock, and accept that a Statamic major bump may strand you. If the only value you need is "radio buttons that look nice," the built-in radio fieldtype with inline: true, or a select plus CP extra_css, gets you there with zero third-party risk. Choose this addon when the visual option card (icons/images/colors) is genuinely the point.vendor/composer/installed.json for the package, confirm it declares extra.statamic, then php artisan statamic:stache:clear — blueprint changes are stache-cached and stale blueprints produce confusing fieldtype errors.Cmd/Ctrl+Shift+R). If the field renders as an empty box or a broken Vue component, the compiled assets didn't load. If a vendor:publish config tag exists (php artisan vendor:publish --tag=button-box), check what it publishes — some addons let you override the Vue component, but recompiling an addon's JS is fragile; prefer subclassing the PHP fieldtype or wrapping the output in your own partial.options: { 1: 'One', 2: 'Two' } becomes integers, not strings, so hero_layout == '1' fails. Quote numeric keys ('1': One) or use word keys everywhere.{{ if hero_layout }} guards the case where the client never picked anything; without a default: and without that guard you'll render nothing.{{ hero_layout }} for display; you'll then be stuck when a client asks to rename "Split" to "Two column." Keep keys stable and map to labels at render time.app/Fieldtypes/ and extend it rather than editing vendor/. You get project-specific behaviour (extra config, custom augmentation) that survives composer update.How can I help you explore Laravel packages today?