Checkboxes and Radio Buttons
Checkboxes and radio buttons use a similar helper pattern as other form elements, with special handling for checked states.
Always do this:
- In your view: Use
value="1"for checkboxes - In your controller: Convert POST data to boolean for views, integer for database
- In your database: Store as
0or1
Checkboxes
Use :
form_checkbox($name, $value = '1', $checked = false, $attributes = []);Parameters
$name(string, required) - The name attribute for the checkbox$value(string|bool|int, optional) - The value attribute. Defaults to'1'$checked(mixed, optional) - Whether the checkbox should be checked. Defaults tofalse$attributes(array, optional) - Additional HTML attributes. Defaults to[]
Recommended Pattern (Best Practice)
For accessibility and improved usability, always wrap the checkbox input directly within the HTML <label> element. This allows users to click the text to toggle the checkbox, increasing the target area.
Note on Validity: Placing the input inside the label (implicit association) is perfectly valid HTML5 and the industry-standard best practice for these elements.
<?php
echo '<label>'; // Start the label wrapper
echo form_checkbox('subscribe', 1, $subscribe_checked);
echo ' Newsletter Subscription'; // Place the text after the input
echo '</label>'; // Close the label wrapper
?>The Checkbox Reality
Unchecked checkboxes don't submit any data. This is HTML behavior, not Trongate.
When a form submits:
- Checked checkbox → POST contains
subscribe='1' - Unchecked checkbox → POST contains no
subscribefield
// After form submission:
$raw_value = post('subscribe', true);
// If checked: returns '1'
// If unchecked: returns '' (empty string)Here's something crucial: unchecked checkboxes don't submit anything.
If a checkbox is checked, the form submits its value. If unchecked, the field doesn't appear in the POST data at all.
// Checkbox was checked
post('subscribe', true); // Returns '1' (or whatever value you set)
// Checkbox was unchecked
post('subscribe', true); // Returns '' (empty string)This is why you often see this pattern:
// In controller (submit method)
$data['subscribe'] = (int) (bool) post('subscribe', true);
// Converts to 1 if checked, 0 if uncheckedThe Complete Pattern
Step 1: View File (Use Wrapping Pattern)
<?php
echo '<label>';
echo form_checkbox('newsletter', 1, $newsletter_checked);
echo ' Newsletter Subscription';
echo '</label>';
?>Important: The third parameter ($newsletter_checked) must be true or false.
Step 2: Controller (Two different conversions)
Your controller needs to handle data differently depending on whether it's going to the view or to the database.
class Members extends Trongate {
// Display form (data goes TO view)
public function create(): void {
$update_id = segment(3, 'int');
if ($update_id > 0 && REQUEST_TYPE === 'GET') {
// Editing existing record
$user = $this->db->get_where($update_id, 'users');
$data['newsletter_checked'] = (bool) $user->newsletter;
} else {
// New form OR redisplay after validation error
$data['newsletter_checked'] = (bool) post('newsletter', true);
}
$this->view('user_form', $data);
}
// Process submission (data goes TO database)
public function submit(): void {
$this->validation->set_rules('email', 'email address', 'required|valid_email');
$result = $this->validation->run();
if ($result === true) {
$data['email'] = post('email', true);
// Convert for database: 1 (checked) or 0 (unchecked)
$data['newsletter'] = (int) (bool) post('newsletter', true);
$update_id = segment(3, 'int');
if ($update_id > 0) {
$this->db->update($update_id, $data, 'users');
set_flashdata('User updated');
} else {
$this->db->insert($data, 'users');
set_flashdata('User created');
}
redirect('users/manage');
} else {
$this->create(); // Redisplay form with errors
// Note: create() method fetches posted data for $newsletter_checked
}
}
}Step 3: Database Schema
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
email VARCHAR(255),
newsletter TINYINT(1) DEFAULT 0 -- 0 = no, 1 = yes
);Two Different Conversions
When working with checkboxes the type of conversion that happens differs, depending on whether the goal is to render a view file or enter a checkbox value into a database.
| Destination | Needs | Conversion | Result |
|---|---|---|---|
| View (form_checkbox) | Boolean | (bool) post('field', true) |
true or false |
| Database | Integer 0/1 | (int) (bool) post('field', true) |
1 or 0 |
Common Pitfalls
Never use string values for checkboxes.
// ❌ CONFUSING
echo form_checkbox('newsletter', 'yes');// Then you need messy checks:
$value = post('newsletter', true); // 'yes' or ''
$is_checked = ($value === 'yes'); // Have to check string
$for_db = (int) ($value === 'yes'); // Even more complexDo this: Always use 1 as the value
// ✅ CLEAR
echo form_checkbox('newsletter', 1, $newsletter_checked);// Simple conversions:
$for_view = (bool) post('newsletter', true); // true/false
$for_db = (int) (bool) post('newsletter', true); // 1/0Radio Buttons
Radio buttons are simpler - they always submit a value. You should also wrap the radio input within the <label> element for accessibility.
form_radio($name, $value = '', $checked = false, $attributes = []);Parameters
$name(string, required) - The name attribute for the radio button$value(string|bool|int, optional) - The value attribute. Defaults to''$checked(mixed, optional) - Whether the radio button should be checked. Defaults tofalse$attributes(array, optional) - Additional HTML attributes. Defaults to[]
Radio Group Example (Recommended Pattern)
<?php
$status_options = [
'active' => 'Active',
'inactive' => 'Inactive',
'pending' => 'Pending'
];
foreach ($status_options as $value => $label) {
$is_checked = ($current_status === $value);
echo '<label>';
echo form_radio('status', $value, $is_checked);
echo ' ' . $label;
echo '</label>';
}
?>// Controller - both view and database use the same value
public function create(): void {
$update_id = segment(3, 'int');
if ($update_id > 0 && REQUEST_TYPE === 'GET') {
$record = $this->db->get_where($update_id, 'items');
$data['current_status'] = $record->status;
} else {
$data['current_status'] = post('status', true);
}
$this->view('form', $data);
}
public function submit(): void {
// Same value works for both view and database
$data['status'] = post('status', true);
$this->db->insert($data, 'items');
}Multiple Checkboxes
For multiple selections, store as JSON array:
<?php
$categories = ['web', 'mobile', 'design', 'marketing'];
$selected_cats = $selected_categories ?? [];
foreach ($categories as $category) {
$is_checked = in_array($category, $selected_cats, true);
echo '<label>';
echo form_checkbox('categories[]', $category, $is_checked);
echo ' ' . ucfirst($category);
echo '</label>';
}
?>// Controller
public function submit(): void {
$selected = post('categories', true) ?: []; // Array or empty array
$data['categories'] = json_encode($selected);
$this->db->insert($data, 'projects');
}Quick Reference
| Element | View Code | To View (boolean) | To Database |
|---|---|---|---|
| Checkbox | <label>...form_checkbox('field', 1, $checked)...</label> |
(bool) post('field', true) |
(int) (bool) post('field', true) |
| Radio | <label>...form_radio('field', 'value', $checked)...</label> |
post('field', true) |
post('field', true) |
| Text Input | form_input('field', $value) |
post('field', true) |
post('field', true) |
Remember: Checkboxes are the only form element that needs different handling for views vs. databases. Everything else uses the same value for both.
We're continually improving the Trongate documentation. If anything is incorrect, unclear, incomplete, or could be better, we'd genuinely appreciate your input.
Share your thoughts in the Documentation Feedback.