Disabled (previous lesson) shows a field but blocks editing. #access goes further — it removes the element from the rendered output entirely, as if it were never in the array at all. Where disabled says "you can see this but not change it," #access says "you don't get to know this exists."
What you'll learn in this lesson
- #access's boolean effect: element present or genuinely absent
- Permission-based visibility, the most common real use case
- Why #access is safer than manually skipping array keys with an if-statement
Permission-gated visibility
$form['admin_notes'] = [
'#type' => 'textarea',
'#title' => $this->t('Internal notes (admin only)'),
'#access' => $this->currentUser()->hasPermission('administer content'),
];
if ($has_permission) { $form['admin_notes'] = [...]; } — but #access => FALSE is the more robust, idiomatic pattern: it works consistently even when other code (a hook_form_alter() from another module) might add fields unconditionally, and it explicitly documents the access rule right on the element itself rather than in surrounding control flow that's easy to miss when a form gets modified later.#access and tampering — a different story than #disabled
// Genuinely NOT rendered at all when access is FALSE — but be aware:
$form['admin_notes'] = [
'#type' => 'textarea',
'#access' => FALSE, // Element removed from output entirely.
];
Because the element is genuinely absent from the rendered form, there's no HTML for an attacker to even target for tampering the way there theoretically could be with a merely-hidden field. This makes #access the right tool specifically when a field should be completely invisible to unauthorized users, not just visible-but-locked the way #disabled leaves it.
Combining with other conditions
$form['delete_button'] = [
'#type' => 'submit',
'#value' => $this->t('Delete'),
'#access' => $entity->access('delete') && !$entity->isNew(),
];
#access takes any boolean expression — combine multiple conditions (an entity-level access check plus a state check like "isn't a brand-new unsaved entity") into one clear, explicit rule right on the element.
Quick check: you need a field that should be completely invisible to most users but visible-and-locked (read-only) for administrators specifically. Would you use #access alone, or #access combined with #disabled? If you said combined — #access controls whether administrators see it at all versus other users, and #disabled (for the administrators who do see it) could further prevent editing if it's meant to be informational even for them — you've understood how these two properties compose rather than being mutually exclusive alternatives.
Key takeaways
- #access controls whether an element renders at all — FALSE means genuinely absent from output, unlike #disabled's visible-but-locked state.
- Prefer #access over conditionally skipping array keys — it's more robust against interaction with other code that might alter the form.
- #access accepts any boolean expression, letting you combine multiple conditions into one explicit rule on the element itself.
Coming up next
You've now covered individual element control. Last in this section: grouping related elements visually with collapsible details containers.