Skip to main content

FormControl

Die FormControl-Komponente dient als Container für Formularelemente und bietet eine konsistente Struktur für Labels, Hilfetexte und Fehlermeldungen. Sie stellt einen Context bereit, der von untergeordneten Komponenten wie Input, Select und Checkbox genutzt werden kann.

Import

import { FormControl, FormLabel, FormHelperText, FormErrorMessage } from '@smolitux/core';

Verwendung

Einfaches Formularfeld

<FormControl>
<FormLabel>Name</FormLabel>
<Input placeholder="Geben Sie Ihren Namen ein" />
<FormHelperText>Bitte geben Sie Ihren vollständigen Namen ein.</FormHelperText>
</FormControl>

Formularfeld mit Fehlermeldung

<FormControl isInvalid={!!errors.email}>
<FormLabel>E-Mail</FormLabel>
<Input
type="email"
placeholder="name@beispiel.de"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
{errors.email ? (
<FormErrorMessage>{errors.email}</FormErrorMessage>
) : (
<FormHelperText>Wir werden Ihre E-Mail niemals weitergeben.</FormHelperText>
)}
</FormControl>

Deaktiviertes Formularfeld

<FormControl isDisabled>
<FormLabel>Benutzername</FormLabel>
<Input defaultValue="max.mustermann" />
<FormHelperText>Der Benutzername kann nicht geändert werden.</FormHelperText>
</FormControl>

Erforderliches Formularfeld

<FormControl isRequired>
<FormLabel>Passwort</FormLabel>
<Input type="password" />
<FormHelperText>Das Passwort muss mindestens 8 Zeichen lang sein.</FormHelperText>
</FormControl>

Formularfeld mit verschiedenen Größen

<FormControl size="sm">
<FormLabel>Klein</FormLabel>
<Input placeholder="Kleines Eingabefeld" />
</FormControl>

<FormControl size="md">
<FormLabel>Mittel</FormLabel>
<Input placeholder="Mittleres Eingabefeld" />
</FormControl>

<FormControl size="lg">
<FormLabel>Groß</FormLabel>
<Input placeholder="Großes Eingabefeld" />
</FormControl>

Formularfeld mit verschiedenen Varianten

<FormControl variant="default">
<FormLabel>Standard</FormLabel>
<Input placeholder="Standard-Eingabefeld" />
</FormControl>

<FormControl variant="filled">
<FormLabel>Gefüllt</FormLabel>
<Input placeholder="Gefülltes Eingabefeld" />
</FormControl>

<FormControl variant="outlined">
<FormLabel>Umrandet</FormLabel>
<Input placeholder="Umrandetes Eingabefeld" />
</FormControl>

Formularfeld mit verschiedenen Label-Positionen

<FormControl labelPosition="top">
<FormLabel>Label oben</FormLabel>
<Input placeholder="Label oben" />
</FormControl>

<FormControl labelPosition="left">
<FormLabel>Label links</FormLabel>
<Input placeholder="Label links" />
</FormControl>

<FormControl labelPosition="floating">
<Input placeholder="Schwebendes Label" />
<FormLabel>Schwebendes Label</FormLabel>
</FormControl>

Formularfeld mit erfolgreichem Zustand

<FormControl isSuccess>
<FormLabel>Benutzername</FormLabel>
<Input value="max.mustermann" />
<FormHelperText>Benutzername ist verfügbar!</FormHelperText>
</FormControl>

Props

FormControl

PropTypStandardBeschreibung
idstring-ID für das Formularfeld
isDisabledbooleanfalseDeaktiviert das Formularfeld
isRequiredbooleanfalseMarkiert das Formularfeld als erforderlich
isInvalidbooleanfalseZeigt den Fehlerzustand an
isValidbooleanfalseZeigt den gültigen Zustand an
isSuccessbooleanfalseZeigt den erfolgreichen Zustand an
isReadOnlybooleanfalseMacht das Formularfeld schreibgeschützt
isLoadingbooleanfalseZeigt einen Ladezustand an
size'xs' | 'sm' | 'md' | 'lg''md'Größe des Formularfelds
variant'default' | 'filled' | 'outlined' | 'unstyled''default'Visuelle Variante des Formularfelds
labelPosition'top' | 'left' | 'right' | 'bottom' | 'floating''top'Position des Labels
labelstring-Text für das Label (Alternative zu FormLabel)
helperTextReactNode-Hilfetext (Alternative zu FormHelperText)
errorMessageReactNode-Fehlermeldung (Alternative zu FormErrorMessage)
successMessageReactNode-Erfolgsmeldung
namestring-Name des Formularfelds
classNamestring-Zusätzliche CSS-Klassen

FormLabel

PropTypStandardBeschreibung
htmlForstring-ID des zugehörigen Formularelements
requiredIndicatorReactNode*Symbol für erforderliche Felder
optionalIndicatorReactNode(optional)Text für optionale Felder
showOptionalIndicatorbooleanfalseZeigt den optionalen Indikator an
classNamestring-Zusätzliche CSS-Klassen

FormHelperText

PropTypStandardBeschreibung
classNamestring-Zusätzliche CSS-Klassen

FormErrorMessage

PropTypStandardBeschreibung
iconReactNode-Icon für die Fehlermeldung
classNamestring-Zusätzliche CSS-Klassen

useFormControl Hook

Der useFormControl Hook ermöglicht den Zugriff auf den FormControl-Context in benutzerdefinierten Komponenten.

import { useFormControl } from '@smolitux/core';

function CustomInput(props) {
const { isDisabled, isRequired, isInvalid, id } = useFormControl();

return (
<input
id={id}
disabled={isDisabled}
required={isRequired}
aria-invalid={isInvalid}
{...props}
className={`custom-input ${isInvalid ? 'custom-input-error' : ''}`}
/>
);
}

Barrierefreiheit

Die FormControl-Komponente ist für Barrierefreiheit optimiert:

  • Korrekte Verknüpfung von Labels und Formularfeldern über IDs
  • Verwendung von aria-invalid für Fehlerzustände
  • Unterstützung für aria-describedby für Hilfetexte und Fehlermeldungen
  • Visuelles Feedback für verschiedene Zustände (Fehler, Erfolg, deaktiviert)

Beispiele

Formular mit Validierung

import { useState } from 'react';
import {
FormControl,
FormLabel,
FormHelperText,
FormErrorMessage,
Input,
Button
} from '@smolitux/core';

function ValidationForm() {
const [values, setValues] = useState({
name: '',
email: '',
password: ''
});

const [errors, setErrors] = useState({});
const [isSubmitting, setIsSubmitting] = useState(false);

const handleChange = (e) => {
const { name, value } = e.target;
setValues({
...values,
[name]: value
});
};

const validate = () => {
const newErrors = {};

if (!values.name) {
newErrors.name = 'Name ist erforderlich';
}

if (!values.email) {
newErrors.email = 'E-Mail ist erforderlich';
} else if (!/\S+@\S+\.\S+/.test(values.email)) {
newErrors.email = 'E-Mail ist ungültig';
}

if (!values.password) {
newErrors.password = 'Passwort ist erforderlich';
} else if (values.password.length < 8) {
newErrors.password = 'Passwort muss mindestens 8 Zeichen lang sein';
}

setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};

const handleSubmit = (e) => {
e.preventDefault();

if (validate()) {
setIsSubmitting(true);

// Simuliere API-Aufruf
setTimeout(() => {
alert('Formular erfolgreich abgesendet!');
setIsSubmitting(false);
}, 1500);
}
};

return (
<form onSubmit={handleSubmit}>
<FormControl isInvalid={!!errors.name} isRequired mb={4}>
<FormLabel>Name</FormLabel>
<Input
name="name"
value={values.name}
onChange={handleChange}
/>
{errors.name ? (
<FormErrorMessage>{errors.name}</FormErrorMessage>
) : (
<FormHelperText>Geben Sie Ihren vollständigen Namen ein.</FormHelperText>
)}
</FormControl>

<FormControl isInvalid={!!errors.email} isRequired mb={4}>
<FormLabel>E-Mail</FormLabel>
<Input
name="email"
type="email"
value={values.email}
onChange={handleChange}
/>
{errors.email ? (
<FormErrorMessage>{errors.email}</FormErrorMessage>
) : (
<FormHelperText>Wir werden Ihre E-Mail niemals weitergeben.</FormHelperText>
)}
</FormControl>

<FormControl isInvalid={!!errors.password} isRequired mb={6}>
<FormLabel>Passwort</FormLabel>
<Input
name="password"
type="password"
value={values.password}
onChange={handleChange}
/>
{errors.password ? (
<FormErrorMessage>{errors.password}</FormErrorMessage>
) : (
<FormHelperText>Das Passwort muss mindestens 8 Zeichen lang sein.</FormHelperText>
)}
</FormControl>

<Button type="submit" isLoading={isSubmitting}>
Registrieren
</Button>
</form>
);
}

Formularfeld mit benutzerdefiniertem Label

<FormControl>
<FormLabel>
<div className="flex items-center">
<Icon name="user" className="mr-2" />
<span>Benutzerprofil</span>
<Tooltip content="Informationen zu Ihrem Benutzerprofil">
<Icon name="info" className="ml-2 text-gray-400" />
</Tooltip>
</div>
</FormLabel>
<Input placeholder="Benutzername" />
</FormControl>

Formularfeld mit Charakterzähler

function CharacterCounter() {
const [value, setValue] = useState('');
const maxLength = 100;

const handleChange = (e) => {
setValue(e.target.value);
};

return (
<FormControl>
<FormLabel>Beschreibung</FormLabel>
<Textarea
value={value}
onChange={handleChange}
maxLength={maxLength}
placeholder="Beschreiben Sie sich kurz..."
/>
<div className="flex justify-end mt-1 text-sm text-gray-500">
{value.length}/{maxLength} Zeichen
</div>
</FormControl>
);
}