How to Handle Form Validation Patterns with Astryx FieldStatus
Use the Field component with validationPattern for automatic validation, or render FieldStatus directly with type, message, and variant props for custom control.
Astryx provides a dedicated FieldStatus component that centralizes visual feedback for form-field validation. The component integrates with the Field wrapper to display error, warning, or success states while ensuring WCAG-compliant accessibility through screen-reader announcements.
Understanding the FieldStatus Architecture
The validation flow in Astryx follows a clear three-layer architecture implemented across packages/core/src/Field/Field.tsx and packages/core/src/FieldStatus/FieldStatus.tsx.
1. Validation Logic (Your Code)
Your application determines whether a value passes validation. This can use regex patterns, custom functions, or server-side checks.
2. Field Component (Wrapper Layer)
The Field component receives validation state through props: status, statusMessage, and statusVariant. According to packages/core/src/Field/Field.tsx, these props forward directly to the internal FieldStatus renderer.
3. FieldStatus Component (Presentation Layer)
Located at packages/core/src/FieldStatus/FieldStatus.tsx, this component handles:
- Visual rendering (icons, colors, typography)
- Variant selection:
attached(inlinebelow input) ordetached(floating box) - Screen-reader announcements via the
useAnnouncehook - StyleX token application for color-blind-safe theming
Automatic Validation with Field
The simplest approach uses Field's built-in validationPattern prop. The component derives type, message, and rendering automatically.
import { Field } from '@astryx-design/core';
function UsernameInput() {
const [value, setValue] = React.useState('');
return (
<Field
label="Username"
value={value}
onChange={setValue}
validationPattern={/^[a-zA-Z0-9]{3,12}$/}
validationMessage="Username must be 3-12 alphanumeric characters."
/>
);
}
When validationPattern fails, Field internally constructs:
status: 'error'statusMessage: your custom message or default "Invalid input"- Renders
FieldStatuswith appropriate styling
Manual FieldStatus Control
For complex validation scenarios, render FieldStatus directly. This pattern appears in packages/core/src/FieldStatus/FieldStatus.tsx as the core use case.
import { FieldStatus } from '@astryx-design/core';
function EmailInput({ value, onChange }) {
const isValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
return (
<div>
<input
type="email"
value={value}
onChange={onChange}
aria-describedby="email-status"
/>
<FieldStatus
id="email-status"
type={isValid ? 'success' : 'error'}
message={isValid
? 'Email looks good!'
: 'Please enter a valid email address.'
}
variant="detached"
/>
</div>
);
}
Variant Selection: Attached vs. Detached
The variant prop controls layout behavior as defined in the FieldStatus source:
| Variant | Behavior | Use Case |
|---|---|---|
| attached | Renders as inline element below the input, inheriting field width | Compact forms, immediate feedback |
| detached | Floating box with icon, can be positioned independently | Complex forms, summary panels |
// Attached variant example from packages/core/src/Field/Field.tsx usage
<Field
label="Password"
value={password}
onChange={setPassword}
status={strength === 'strong' ? 'success' : 'error'}
statusMessage={strength === 'strong'
? 'Strong password'
: 'Include uppercase and number'
}
statusVariant="attached"
/>
Accessibility Implementation: useAnnounce Hook
The FieldStatus component imports useAnnounce from packages/core/src/hooks/useAnnounce.ts to manage live-region announcements. This implementation detail ensures:
- Messages announce on initial mount
- Changes re-announce automatically
- Persistent live regions survive component unmounting
Per WCAG guidelines, the detached variant always renders:
- Visual icon (
aria-hidden="true") - Text message (visible and announced)
- Color coding (supplemental, never sole indicator)
Theming and Color Tokens
FieldStatus applies StyleX tokens defined in packages/core/src/FieldStatus/FieldStatus.tsx. Key token categories:
--color-error-muted/--color-error/--color-error-emphasis--color-warning-muted/--color-warning/--color-warning-emphasis--color-success-muted/--color-success/--color-success-emphasis
These map to type="error", type="warning", and type="success" respectively.
Complete Multi-Field Validation Example
import { Field, FieldStatus } from '@astryx-design/core';
function RegistrationForm() {
const [email, setEmail] = React.useState('');
const [password, setPassword] = React.useState('');
const emailValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
const pwdStrong = /^(?=.*[A-Z])(?=.*\d).{8,}$/.test(password);
return (
<form>
<Field
label="Email"
value={email}
onChange={setEmail}
status={email ? (emailValid ? 'success' : 'error') : undefined}
statusMessage={emailValid ? 'Valid email' : 'Invalid email format'}
statusVariant="attached"
/>
<Field
label="Password"
value={password}
onChange={setPassword}
type="password"
/>
{/* Conditional detached status for password requirements */}
{password && !pwdStrong && (
<FieldStatus
type="warning"
message="Password needs 8+ characters, 1 uppercase, 1 number"
variant="detached"
/>
)}
</form>
);
}
Server-Side Validation Integration
For asynchronous validation, manually control FieldStatus props based on API responses:
const [serverError, setServerError] = React.useState(null);
// After submit
const response = await validateOnServer(formData);
if (!response.valid) {
setServerError(response.message);
}
// Render
{serverError && (
<FieldStatus
type="error"
message={serverError}
variant="detached"
/>
)}
Summary
FieldwithvalidationPatternprovides automatic regex-based validation with minimal codeFieldStatusdirect rendering offers full control over validation logic and presentationvariant="attached"integrates seamlessly withFieldfor inline feedbackvariant="detached"creates independent status displays for complex UIsuseAnnouncehook ensures all validation states are announced to screen readers- StyleX tokens guarantee color-blind-safe, theme-consistent styling
Frequently Asked Questions
How do I customize the error message for regex pattern validation?
Pass the validationMessage prop to Field. When validationPattern fails, this string replaces the default "Invalid input" message. For dynamic messages based on specific failure conditions, use manual FieldStatus rendering instead.
Can FieldStatus announce to screen readers without visual display?
No. The FieldStatus component couples visual and auditory feedback by design. For invisible announcements, use the useAnnounce hook directly from packages/core/src/hooks/useAnnounce.ts with role="status" or role="alert" on a visually hidden element.
What happens if both attached and detached variants are used together?
The Field component renders only one FieldStatus instance internally. When using manual FieldStatus alongside Field, ensure unique id attributes and aria-describedby references to prevent duplicate announcements.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →