Radio
PandaPanel\Forms\Components\Radio memungkinkan user memilih satu value dari beberapa pilihan dan menampilkan seluruh pilihan sekaligus. Data yang disimpan sama seperti select, tetapi Radio menggunakan lebih banyak ruang agar user dapat membandingkan seluruh pilihan tanpa membuka dropdown. Gunakan ketika hanya ada sekitar tiga atau empat pilihan; untuk daftar yang lebih panjang gunakan Select.
Contoh minimal
use PandaPanel\Forms\Components\Radio;
use PandaPanel\Forms\FormSchema;
FormSchema::make()->schema([
Radio::make('plan')
->options([
'free' => 'Free',
'pro' => 'Pro',
'enterprise' => 'Enterprise',
])
->required(),
]);2
3
4
5
6
7
8
9
10
11
12
Method
public function options(array $options): self // array<array-key, string>
public function descriptions(array $descriptions): self // array<array-key, string>
public function inline(bool $inline = true): self // default: false2
3
| Method | Default | Dampak |
|---|---|---|
options() | [] | pilihan yang di-key oleh stored value; sekaligus menjadi validation whitelist |
descriptions() | [] | teks di bawah label option, menggunakan key yang sama |
inline() | false | menata pilihan sebagai wrapping row, bukan column |
use PandaPanel\Forms\Components\Radio;
Radio::make('plan')
->label('Subscription')
->options([
'free' => 'Free',
'pro' => 'Pro',
'enterprise' => 'Enterprise',
])
->descriptions([
'pro' => 'Everything, billed monthly',
'enterprise' => 'Volume pricing and a named contact',
])
->default('free')
->helperText('Changing this takes effect at the next renewal.');2
3
4
5
6
7
8
9
10
11
12
13
14
15
descriptions() menggunakan option key, bukan posisi. Option yang tidak memiliki description cukup tidak diberi entry. Kedua array menerima integer key, sehingga dapat digunakan untuk column yang memakai numeric-backed value:
use PandaPanel\Forms\Components\Radio;
Radio::make('priority')
->options([1 => 'Low', 2 => 'Normal', 3 => 'High'])
->inline();2
3
4
5
Validasi
Options yang dideklarasikan menjadi whitelist. Value yang tidak pernah ditawarkan schema bukan sekadar unexpected, tetapi invalid:
use PandaPanel\Forms\Components\Radio;
use PandaPanel\Forms\FormSchema;
$rules = FormSchema::make()
->schema([Radio::make('plan')->options(['free' => 'Free', 'pro' => 'Pro'])])
->validationRules();
// ['plan' => ['nullable', Illuminate\Validation\Rules\In]]
// The rule renders as: in:"free","pro"2
3
4
5
6
7
8
9
Rule dibuat dengan Illuminate\Validation\Rule::in() terhadap option key yang di-cast menjadi string. Karena itu [1 => 'Low'] menghasilkan in:"1" dan form yang mengirim '1' tetap lolos.
Jika tidak ada option yang dideklarasikan, rule in sama sekali tidak dibuat. Radio group dengan options kosong merender tanpa pilihan dan hanya divalidasi oleh nullable/required. Ini penting jika options berasal dari query yang mungkin tidak menghasilkan record.
Hydration dan bentuk value
protected function castForForm(mixed $value): string|int|nullString atau integer diteruskan. Nilai lain seperti boolean, enum instance, atau array menjadi null.
Pada wire, seluruh option value menjadi string:
use PandaPanel\Forms\Components\Radio;
Radio::make('plan')
->options(['free' => 'Free', 'pro' => 'Pro'])
->descriptions(['pro' => 'Everything, billed monthly'])
->inline()
->toArray(null, 'create');2
3
4
5
6
7
{
"type": "radio",
"inline": true,
"options": [
{ "value": "free", "label": "Free", "description": null },
{ "value": "pro", "label": "Pro", "description": "Everything, billed monthly" }
]
}2
3
4
5
6
7
8
Control membandingkan selection sebagai string. Key 1 di database dan '1' di form dianggap option yang sama, bukan dua option berbeda.
Bekerja dengan enum
Backed enum tidak dapat diberikan langsung ke options(), karena method tersebut mengharapkan array<array-key, string>. Bentuk map-nya terlebih dahulu, lalu cast kembali saat keluar jika column mengharapkan enum:
use App\Enums\Priority;
use Illuminate\Database\Eloquent\Model;
use PandaPanel\Forms\Components\Radio;
Radio::make('priority')
->options(array_combine(
array_map(static fn (Priority $case): string => $case->value, Priority::cases()),
array_map(static fn (Priority $case): string => $case->label(), Priority::cases()),
))
->formatUsing(static fn (mixed $value, ?Model $record): ?string => $value instanceof Priority
? $value->value
: (is_string($value) ? $value : null))
->mutateUsing(static fn (mixed $value, ?Model $record): ?Priority => is_string($value)
? Priority::tryFrom($value)
: null);2
3
4
5
6
7
8
9
10
11
12
13
14
15
formatUsing() dibutuhkan karena enum-cast attribute menghasilkan instance Priority, sedangkan castForForm() akan mengembalikan null untuk object tersebut.
Mengendalikan field lain
Radio group cocok menjadi sumber declarative condition. Equals dan In dapat bekerja langsung di browser tanpa request:
use PandaPanel\Forms\Components\Radio;
use PandaPanel\Forms\Components\TextInput;
use PandaPanel\Forms\Enums\ConditionOperator;
Radio::make('plan')->options(['free' => 'Free', 'pro' => 'Pro', 'enterprise' => 'Enterprise']),
TextInput::make('seats')
->visibleWhen('plan', ConditionOperator::In, ['pro', 'enterprise']),
TextInput::make('purchase_order')
->visibleWhen('plan', ConditionOperator::Equals, 'enterprise'),2
3
4
5
6
7
8
9
10
11
Jika perubahan option memerlukan hasil yang harus dihitung server, gunakan live().
Data yang dikirim ke frontend
interface DescribedOption extends SelectOption {
value: string;
label: string;
description: string | null;
}
interface RadioFieldDefinition extends BaseFieldDefinition {
type: 'radio';
options: DescribedOption[];
inline: boolean;
}2
3
4
5
6
7
8
9
10
11
Hal yang perlu diperhatikan
Submitted value berupa string. Server menerima '1', bukan 1. Laravel dapat menulis string tersebut ke integer column, tetapi strict comparison dalam hook tidak akan match. Cast melalui mutateUsing() jika tipe value penting.
Tidak ada options berarti tidak ada whitelist. options([]) melewati rule in sepenuhnya. Jika options berasal dari data dinamis, tangani kondisi kosong secara eksplisit dan jangan menganggap rule tetap melindungi input.
Options tidak searchable dan tidak lazy. Seluruh option diserialisasi bersama form. Daftar yang cukup panjang hingga membutuhkan search box lebih tepat menggunakan Select dengan searchable(), yang mengambil data melalui options endpoint.
descriptions() tidak membuat option baru. Description untuk key yang tidak ada di options() akan diabaikan.
Radio tidak dapat dikosongkan kembali oleh user. Tidak ada control “none”; setelah option dipilih, user tidak bisa kembali ke null. Jika perlu, buat empty state sebagai option nyata lalu map ke null saat keluar:
use Illuminate\Database\Eloquent\Model;
use PandaPanel\Forms\Components\Radio;
Radio::make('assignee_kind')
->options([
'none' => 'Unassigned',
'user' => 'A person',
'team' => 'A team',
])
->default('none')
->mutateUsing(static fn (mixed $value, ?Model $record): ?string => $value === 'none'
? null
: (is_string($value) ? $value : null));2
3
4
5
6
7
8
9
10
11
12
13
inline() hanya mengubah layout. Method ini hanya membuat options tersusun dalam row; value, rules, dan data yang diterima server tidak berubah.
Lihat juga
- Select — data yang sama, dengan search dan relationships
- Checkbox — boolean tunggal
- Toggle
- Visibility —
Equals,In, dan operator lainnya - Live Fields
- Validation
- Forms and Schemas