Atlas Forms
useFormVisibility Hook
The useFormVisibility hook gives custom player components access to the form's visibility system. It returns two functions: isVisible(controlId) checks a single control, and getVisibleControls() returns all controls that are currently visible.
Hook Return Type
import { useFormVisibility } from '@atlas-forms/player-components-react';
interface FormVisibilityState {
/**
* Returns true when the control should be rendered.
* Evaluates both modeVisibilitySettings and visibilityRule.
*/
isVisible: (controlId: string) => boolean;
/**
* Returns all controls for which isVisible() returns true.
* Result is recalculated on every value change.
*/
getVisibleControls: () => FormControl[];
}
isVisible(controlId)
const { isVisible } = useFormVisibility();
// Usage — filter before rendering
const controls = schema.controls ?? [];
return (
<div>
{controls
.filter(c => isVisible(c.id))
.map(c => <ControlRenderer key={c.id} control={c} />)
}
</div>
);
getVisibleControls()
const { getVisibleControls } = useFormVisibility();
// Usage — progress calculation
const visibleControls = getVisibleControls();
const filled = visibleControls.filter(c => {
const v = values[c.id];
return v !== undefined && v !== null && v !== '';
}).length;
const progress = Math.round((filled / visibleControls.length) * 100);
Section-Level Filtering Pattern
For grouped layouts, filter at the section level to avoid rendering empty sections:
const { isVisible } = useFormVisibility();
const schema = engine.getSchema();
return (
<>
{(schema.sections ?? []).map(section => {
// Filter controls for this section
const controls = (schema.controls ?? [])
.filter(c => c.sectionId === section.id && isVisible(c.id));
// Hide the entire section if no controls are visible
if (controls.length === 0) return null;
return (
<div key={section.id} className="section">
<h3>{section.title}</h3>
{controls.map(c => <ControlRenderer key={c.id} control={c} />)}
</div>
);
})}
</>
);
Hook Rules
| Rule | Detail |
|---|---|
| Must be inside FormStateProvider | Throws if called outside the provider context |
| Call once per component | Do not call inside a loop or conditionally — call at the top of the component and pass isVisible down |
| Re-renders on value changes | The hook subscribes to the form context; the component re-renders when any value changes |
| isVisible() is memoised | The function reference is stable; safe to pass as a prop without causing child re-renders from reference inequality |
ControlRenderer Checks Visibility Internally
ControlRenderer already calls isVisible() internally and returns null if the control is not visible. If you are using ControlRenderer, you do not need to pre-filter with isVisible() — it is done for you. Only use isVisible() directly when you need to make layout decisions at the section or container level (e.g., hiding an empty section card).