Skip to content
HyperUI for Flutter requires the Style package — this site itself ships no pub package.

Contact Forms

Ported from HyperUI’s Contact Forms — see Attribution.

Includes a dark: variant — toggle the site theme (top right) to preview it.

class ContactForms1Example extends StatelessWidget {
const ContactForms1Example({super.key});
@override
Widget build(BuildContext context) {
return Style(
'p-6',
child: Style(
'mx-auto max-w-md space-y-4 rounded-lg border border-gray-300 bg-gray-100 p-6 dark:border-gray-600 dark:bg-gray-800',
children: [
Style.empty(
children: [
const Style(
'block text-sm font-medium text-gray-900 dark:text-white',
child: Text('Name'),
),
Style(
'mt-1 w-full rounded-lg border-gray-300 focus:border-indigo-500 focus:outline-none dark:border-gray-600 dark:bg-gray-900 dark:text-white',
child: Builder(
builder: (context) => _buildField(context, hintText: 'Your name'),
),
),
],
),
Style.empty(
children: [
const Style(
'block text-sm font-medium text-gray-900 dark:text-white',
child: Text('Email'),
),
Style(
'mt-1 w-full rounded-lg border-gray-300 focus:border-indigo-500 focus:outline-none dark:border-gray-600 dark:bg-gray-900 dark:text-white',
child: Builder(
builder: (context) => _buildField(
context,
hintText: 'Your email',
keyboardType: TextInputType.emailAddress,
),
),
),
],
),
Style.empty(
children: [
const Style(
'block text-sm font-medium text-gray-900 dark:text-white',
child: Text('Message'),
),
Style(
'mt-1 w-full resize-none rounded-lg border-gray-300 focus:border-indigo-500 focus:outline-none dark:border-gray-600 dark:bg-gray-900 dark:text-white',
child: Builder(
builder: (context) =>
_buildField(context, hintText: 'Your message', maxLines: 4, minLines: 4),
),
),
],
),
Style(
'block w-full rounded-lg border border-indigo-600 bg-indigo-600 px-12 py-3 text-sm font-medium text-white transition-colors hover:bg-transparent hover:text-indigo-600 dark:hover:bg-indigo-700 dark:hover:text-white',
child: const Text('Send Message'),
),
],
),
);
}
}
Widget _buildField(
BuildContext context, {
required String hintText,
TextInputType? keyboardType,
int? maxLines,
int? minLines,
}) {
final isDark = Theme.of(context).brightness == Brightness.dark;
final borderColor = isDark ? tailwindColors['gray']![600]! : tailwindColors['gray']![300]!;
final border = OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(color: borderColor),
);
final baseStyle = Theme.of(context).textTheme.bodyLarge ?? const TextStyle();
return TextFormField(
keyboardType: keyboardType,
maxLines: maxLines,
minLines: minLines,
style: baseStyle.copyWith(
color: isDark ? Colors.white : Colors.black,
letterSpacing: 0,
),
decoration: InputDecoration(
hintText: hintText,
hintStyle: TextStyle(color: tailwindColors['gray']![500], letterSpacing: 0),
isDense: true,
filled: true,
fillColor: isDark ? tailwindColors['gray']![900] : Colors.white,
contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 9),
border: border,
enabledBorder: border,
focusedBorder: border,
),
);
}

Includes a dark: variant — toggle the site theme (top right) to preview it.

class ContactForms2Example extends StatelessWidget {
const ContactForms2Example({super.key});
static const _subjectOptions = <String, String>{
'': 'Select a subject',
'general-inquiry': 'General Inquiry',
'support': 'Support',
'feedback': 'Feedback',
};
static const _priorityOptions = <String, String>{
'': 'Select a priority',
'low': 'Low',
'medium': 'Medium',
'high': 'High',
};
@override
Widget build(BuildContext context) {
return Style(
'p-6',
child: Style(
'mx-auto max-w-md space-y-4 rounded-lg border border-gray-300 bg-gray-100 p-6 dark:border-gray-600 dark:bg-gray-800',
children: [
Style.empty(
children: [
const Style(
'block text-sm font-medium text-gray-900 dark:text-white',
child: Text('Name'),
),
Style(
'mt-1 w-full rounded-lg border-gray-300 focus:border-indigo-500 focus:outline-none dark:border-gray-600 dark:bg-gray-900 dark:text-white',
child: Builder(
builder: (context) => _buildField(context, hintText: 'Your name'),
),
),
],
),
Style.empty(
children: [
const Style(
'block text-sm font-medium text-gray-900 dark:text-white',
child: Text('Email'),
),
Style(
'mt-1 w-full rounded-lg border-gray-300 focus:border-indigo-500 focus:outline-none dark:border-gray-600 dark:bg-gray-900 dark:text-white',
child: Builder(
builder: (context) => _buildField(
context,
hintText: 'Your email',
keyboardType: TextInputType.emailAddress,
),
),
),
],
),
Style.empty(
children: [
const Style(
'block text-sm font-medium text-gray-900 dark:text-white',
child: Text('Subject'),
),
Style(
'mt-1 w-full rounded-lg border-gray-300 focus:border-indigo-500 focus:outline-none dark:border-gray-600 dark:bg-gray-900 dark:text-white',
child: Builder(builder: (context) => _buildSelect(context, _subjectOptions)),
),
],
),
Style.empty(
children: [
const Style(
'block text-sm font-medium text-gray-900 dark:text-white',
child: Text('Priority'),
),
Style(
'mt-1 w-full rounded-lg border-gray-300 focus:border-indigo-500 focus:outline-none dark:border-gray-600 dark:bg-gray-900 dark:text-white',
child: Builder(builder: (context) => _buildSelect(context, _priorityOptions)),
),
],
),
Style.empty(
children: [
const Style(
'block text-sm font-medium text-gray-900 dark:text-white',
child: Text('Message'),
),
Style(
'mt-1 w-full resize-none rounded-lg border-gray-300 focus:border-indigo-500 focus:outline-none dark:border-gray-600 dark:bg-gray-900 dark:text-white',
child: Builder(
builder: (context) =>
_buildField(context, hintText: 'Your message', maxLines: 4, minLines: 4),
),
),
],
),
Style(
'block w-full rounded-lg border border-indigo-600 bg-indigo-600 px-12 py-3 text-sm font-medium text-white transition-colors hover:bg-transparent hover:text-indigo-600 dark:hover:bg-indigo-700 dark:hover:text-white',
child: const Text('Send Message'),
),
],
),
);
}
}
const _chevronSvg =
'''<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 20 20"><path stroke="#6b7280" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M6 8l4 4 4-4"/></svg>''';
OutlineInputBorder _fieldBorder(bool isDark) {
final borderColor = isDark ? tailwindColors['gray']![600]! : tailwindColors['gray']![300]!;
return OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(color: borderColor),
);
}
Widget _buildField(
BuildContext context, {
required String hintText,
TextInputType? keyboardType,
int? maxLines,
int? minLines,
}) {
final isDark = Theme.of(context).brightness == Brightness.dark;
final baseStyle = Theme.of(context).textTheme.bodyLarge ?? const TextStyle();
return TextFormField(
keyboardType: keyboardType,
maxLines: maxLines,
minLines: minLines,
style: baseStyle.copyWith(
color: isDark ? Colors.white : Colors.black,
letterSpacing: 0,
),
decoration: InputDecoration(
hintText: hintText,
hintStyle: TextStyle(color: tailwindColors['gray']![500], letterSpacing: 0),
isDense: true,
filled: true,
fillColor: isDark ? tailwindColors['gray']![900] : Colors.white,
contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 9),
border: _fieldBorder(isDark),
enabledBorder: _fieldBorder(isDark),
focusedBorder: _fieldBorder(isDark),
),
);
}
Widget _buildSelect(BuildContext context, Map<String, String> options) {
final isDark = Theme.of(context).brightness == Brightness.dark;
final baseStyle = Theme.of(context).textTheme.bodyLarge ?? const TextStyle();
final textColor = isDark ? Colors.white : tailwindColors['gray']![900]!;
return Stack(
children: [
DropdownButtonFormField<String>(
initialValue: '',
isExpanded: true,
itemHeight: null,
icon: const SizedBox.shrink(),
style: baseStyle.copyWith(color: textColor, letterSpacing: 0),
decoration: InputDecoration(
isDense: true,
filled: true,
fillColor: isDark ? tailwindColors['gray']![900] : Colors.white,
contentPadding: const EdgeInsets.fromLTRB(12, 8, 40, 8),
border: _fieldBorder(isDark),
enabledBorder: _fieldBorder(isDark),
focusedBorder: _fieldBorder(isDark),
),
items: [
for (final entry in options.entries)
DropdownMenuItem(value: entry.key, child: Text(entry.value)),
],
onChanged: (_) {},
),
Positioned.fill(
child: IgnorePointer(
child: Align(
alignment: Alignment.centerRight,
child: Padding(
padding: const EdgeInsets.only(right: 8),
child: SvgPicture.string(_chevronSvg, width: 24, height: 24),
),
),
),
),
],
);
}

Includes a dark: variant — toggle the site theme (top right) to preview it.

class ContactForms3Example extends StatefulWidget {
const ContactForms3Example({super.key});
@override
State<ContactForms3Example> createState() => _ContactForms3ExampleState();
}
class _ContactForms3ExampleState extends State<ContactForms3Example> {
var _generalInquiry = false;
var _support = false;
var _feedback = false;
var _other = false;
@override
Widget build(BuildContext context) {
return Style(
'p-6',
child: Style(
'mx-auto max-w-md space-y-4 rounded-lg border border-gray-300 bg-gray-100 p-6 dark:border-gray-600 dark:bg-gray-800',
children: [
Style.empty(
children: [
const Style(
'block text-sm font-medium text-gray-900 dark:text-white',
child: Text('Name'),
),
Style(
'mt-1 w-full rounded-lg border-gray-300 focus:border-indigo-500 focus:outline-none dark:border-gray-600 dark:bg-gray-900 dark:text-white',
child: Builder(
builder: (context) => _buildField(context, hintText: 'Your name'),
),
),
],
),
Style.empty(
children: [
const Style(
'block text-sm font-medium text-gray-900 dark:text-white',
child: Text('Email'),
),
Style(
'mt-1 w-full rounded-lg border-gray-300 focus:border-indigo-500 focus:outline-none dark:border-gray-600 dark:bg-gray-900 dark:text-white',
child: Builder(
builder: (context) => _buildField(
context,
hintText: 'Your email',
keyboardType: TextInputType.emailAddress,
),
),
),
],
),
Style.empty(
children: [
const Style(
'block text-sm font-medium text-gray-900 dark:text-white',
child: Text('Inquiry'),
),
Style(
'mt-2 space-y-2',
children: [
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () =>
setState(() => _generalInquiry = !_generalInquiry),
child: Style(
'flex items-center gap-2',
cursor: SystemMouseCursors.click,
children: [
Style(
'size-5 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500 dark:border-gray-600 dark:bg-gray-900 dark:text-white',
formControl: true,
checked: _generalInquiry,
),
const Style(
'block text-sm text-gray-900 dark:text-white',
child: Text('General Inquiry'),
),
],
),
),
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => setState(() => _support = !_support),
child: Style(
'flex items-center gap-2',
cursor: SystemMouseCursors.click,
children: [
Style(
'size-5 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500 dark:border-gray-600 dark:bg-gray-900 dark:text-white',
formControl: true,
checked: _support,
),
const Style(
'block text-sm text-gray-900 dark:text-white',
child: Text('Support'),
),
],
),
),
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => setState(() => _feedback = !_feedback),
child: Style(
'flex items-center gap-2',
cursor: SystemMouseCursors.click,
children: [
Style(
'size-5 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500 dark:border-gray-600 dark:bg-gray-900 dark:text-white',
formControl: true,
checked: _feedback,
),
const Style(
'block text-sm text-gray-900 dark:text-white',
child: Text('Feedback'),
),
],
),
),
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => setState(() => _other = !_other),
child: Style(
'flex items-center gap-2',
cursor: SystemMouseCursors.click,
children: [
Style(
'size-5 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500 dark:border-gray-600 dark:bg-gray-900 dark:text-white',
formControl: true,
checked: _other,
),
const Style(
'block text-sm text-gray-900 dark:text-white',
child: Text('Other'),
),
],
),
),
],
),
],
),
Style.empty(
children: [
const Style(
'block text-sm font-medium text-gray-900 dark:text-white',
child: Text('Message'),
),
Style(
'mt-1 w-full resize-none rounded-lg border-gray-300 focus:border-indigo-500 focus:outline-none dark:border-gray-600 dark:bg-gray-900 dark:text-white',
child: Builder(
builder: (context) =>
_buildField(context, hintText: 'Your message', maxLines: 4, minLines: 4),
),
),
],
),
Style(
'block w-full rounded-lg border border-indigo-600 bg-indigo-600 px-12 py-3 text-sm font-medium text-white transition-colors hover:bg-transparent hover:text-indigo-600 dark:hover:bg-indigo-700 dark:hover:text-white',
child: const Text('Send Message'),
),
],
),
);
}
}
Widget _buildField(
BuildContext context, {
required String hintText,
TextInputType? keyboardType,
int? maxLines,
int? minLines,
}) {
final isDark = Theme.of(context).brightness == Brightness.dark;
final borderColor = isDark ? tailwindColors['gray']![600]! : tailwindColors['gray']![300]!;
final border = OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(color: borderColor),
);
final baseStyle = Theme.of(context).textTheme.bodyLarge ?? const TextStyle();
return TextFormField(
keyboardType: keyboardType,
maxLines: maxLines,
minLines: minLines,
style: baseStyle.copyWith(
color: isDark ? Colors.white : Colors.black,
letterSpacing: 0,
),
decoration: InputDecoration(
hintText: hintText,
hintStyle: TextStyle(color: tailwindColors['gray']![500], letterSpacing: 0),
isDense: true,
filled: true,
fillColor: isDark ? tailwindColors['gray']![900] : Colors.white,
contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 9),
border: border,
enabledBorder: border,
focusedBorder: border,
),
);
}

Includes a dark: variant — toggle the site theme (top right) to preview it.

class ContactForms4Example extends StatelessWidget {
const ContactForms4Example({super.key});
@override
Widget build(BuildContext context) {
return Style(
'p-6',
child: Style(
'mx-auto grid max-w-lg grid-cols-1 gap-4 rounded-lg border border-gray-300 bg-gray-100 p-6 sm:grid-cols-2 dark:border-gray-600 dark:bg-gray-800',
children: [
Style(
'md:col-span-2',
children: [
const Style(
'block text-sm font-medium text-gray-900 dark:text-white',
child: Text('Name'),
),
Style(
'mt-1 w-full rounded-lg border-gray-300 focus:border-indigo-500 focus:outline-none dark:border-gray-600 dark:bg-gray-900 dark:text-white',
child: Builder(
builder: (context) => _buildField(context, hintText: 'Your name'),
),
),
],
),
Style.empty(
children: [
const Style(
'block text-sm font-medium text-gray-900 dark:text-white',
child: Text('Email'),
),
Style(
'mt-1 w-full rounded-lg border-gray-300 focus:border-indigo-500 focus:outline-none dark:border-gray-600 dark:bg-gray-900 dark:text-white',
child: Builder(
builder: (context) => _buildField(
context,
hintText: 'Your email',
keyboardType: TextInputType.emailAddress,
),
),
),
],
),
Style.empty(
children: [
const Style(
'block text-sm font-medium text-gray-900 dark:text-white',
child: Text('Phone'),
),
Style(
'mt-1 w-full rounded-lg border-gray-300 focus:border-indigo-500 focus:outline-none dark:border-gray-600 dark:bg-gray-900 dark:text-white',
child: Builder(
builder: (context) =>
_buildField(context, hintText: 'Your phone', keyboardType: TextInputType.phone),
),
),
],
),
Style(
'md:col-span-2',
children: [
const Style(
'block text-sm font-medium text-gray-900 dark:text-white',
child: Text('Message'),
),
Style(
'mt-1 w-full resize-none rounded-lg border-gray-300 focus:border-indigo-500 focus:outline-none dark:border-gray-600 dark:bg-gray-900 dark:text-white',
child: Builder(
builder: (context) =>
_buildField(context, hintText: 'Your message', maxLines: 4, minLines: 4),
),
),
],
),
Style(
'md:col-span-2',
child: Style(
'block w-full rounded-lg border border-indigo-600 bg-indigo-600 px-12 py-3 text-sm font-medium text-white transition-colors hover:bg-transparent hover:text-indigo-600 dark:hover:bg-indigo-700 dark:hover:text-white',
child: const Text('Send Message'),
),
),
],
),
);
}
}
Widget _buildField(
BuildContext context, {
required String hintText,
TextInputType? keyboardType,
int? maxLines,
int? minLines,
}) {
final isDark = Theme.of(context).brightness == Brightness.dark;
final borderColor = isDark ? tailwindColors['gray']![600]! : tailwindColors['gray']![300]!;
final border = OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(color: borderColor),
);
final baseStyle = Theme.of(context).textTheme.bodyLarge ?? const TextStyle();
return TextFormField(
keyboardType: keyboardType,
maxLines: maxLines,
minLines: minLines,
style: baseStyle.copyWith(
color: isDark ? Colors.white : Colors.black,
letterSpacing: 0,
),
decoration: InputDecoration(
hintText: hintText,
hintStyle: TextStyle(color: tailwindColors['gray']![500], letterSpacing: 0),
isDense: true,
filled: true,
fillColor: isDark ? tailwindColors['gray']![900] : Colors.white,
contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 9),
border: border,
enabledBorder: border,
focusedBorder: border,
),
);
}

Includes a dark: variant — toggle the site theme (top right) to preview it.

class CurrentColorIcon extends StatelessWidget
implements StyleReplacedElementWrapper {
const CurrentColorIcon(this.svg, {super.key});
final String svg;
@override
Widget build(BuildContext context) {
final color = IconTheme.of(context).color ?? const Color(0xFF000000);
return SvgPicture.string(svg, theme: SvgTheme(currentColor: color));
}
}
const _phoneSvg =
'''<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M10.5 1.5H8.25A2.25 2.25 0 0 0 6 3.75v16.5a2.25 2.25 0 0 0 2.25 2.25h7.5A2.25 2.25 0 0 0 18 20.25V3.75a2.25 2.25 0 0 0-2.25-2.25H13.5m-3 0V3h3V1.5m-3 0h3m-3 18.75h3"/></svg>''';
const _envelopeSvg =
'''<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M21.75 6.75v10.5a2.25 2.25 0 0 1-2.25 2.25h-15a2.25 2.25 0 0 1-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0 0 19.5 4.5h-15a2.25 2.25 0 0 0-2.25 2.25m19.5 0v.243a2.25 2.25 0 0 1-1.07 1.916l-7.5 4.615a2.25 2.25 0 0 1-2.36 0L3.32 8.91a2.25 2.25 0 0 1-1.07-1.916V6.75"/></svg>''';
const _locationSvg =
'''<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="m2.25 12 8.954-8.955c.44-.439 1.152-.439 1.591 0L21.75 12M4.5 9.75v10.125c0 .621.504 1.125 1.125 1.125H9.75v-4.875c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21h4.125c.621 0 1.125-.504 1.125-1.125V9.75M8.25 21h8.25"/></svg>''';
class ContactForms5Example extends StatelessWidget {
const ContactForms5Example({super.key});
@override
Widget build(BuildContext context) {
return Style(
'mx-auto max-w-7xl px-4 py-8 sm:px-6 lg:px-8',
child: Style(
'grid grid-cols-1 gap-8 md:grid-cols-2',
children: [
Style(
'md:py-4',
children: [
const Style(
'text-2xl font-bold text-gray-900 sm:text-3xl dark:text-white',
child: Text('Get in touch'),
),
const Style(
'mt-4 text-pretty text-gray-700 dark:text-gray-200',
child: Text(
'Lorem, ipsum dolor sit amet consectetur adipisicing elit. Sed voluptas delectus alias magni velit! Dicta corrupti dignissimos dolor consequatur illum tempore consectetur hic a cupiditate sunt quam, earum nisi aperiam.',
),
),
Style(
'mt-6 space-y-3',
children: [
Style.empty(
children: [
const Style('sr-only', child: Text('Phone number')),
Style(
'grid grid-cols-[24px_1fr] items-center gap-2 text-gray-700 dark:text-gray-200',
children: [
Style('size-5', child: CurrentColorIcon(_phoneSvg)),
const Style(
'font-medium',
child: Text('+1 (555) 123-4567'),
),
],
),
],
),
Style.empty(
children: [
const Style('sr-only', child: Text('Email')),
Style(
'grid grid-cols-[24px_1fr] items-center gap-2 text-gray-700 dark:text-gray-200',
children: [
Style('size-5', child: CurrentColorIcon(_envelopeSvg)),
const Style(
'font-medium',
child: Text('info@example.com'),
),
],
),
],
),
Style.empty(
children: [
const Style('sr-only', child: Text('Location')),
Style(
'grid grid-cols-[24px_1fr] items-center gap-2 text-gray-700 dark:text-gray-200',
children: [
Style('size-5', child: CurrentColorIcon(_locationSvg)),
const Style(
'font-medium',
child: Text('123 Main St, Anytown, USA'),
),
],
),
],
),
],
),
],
),
Style(
'space-y-4 rounded-lg border border-gray-300 bg-gray-100 p-6 dark:border-gray-600 dark:bg-gray-800',
children: [
Style.empty(
children: [
const Style(
'block text-sm font-medium text-gray-900 dark:text-white',
child: Text('Name'),
),
Style(
'mt-1 w-full rounded-lg border-gray-300 focus:border-indigo-500 focus:outline-none dark:border-gray-600 dark:bg-gray-900 dark:text-white',
child: Builder(
builder: (context) => _buildField(context, hintText: 'Your name'),
),
),
],
),
Style.empty(
children: [
const Style(
'block text-sm font-medium text-gray-900 dark:text-white',
child: Text('Email'),
),
Style(
'mt-1 w-full rounded-lg border-gray-300 focus:border-indigo-500 focus:outline-none dark:border-gray-600 dark:bg-gray-900 dark:text-white',
child: Builder(
builder: (context) => _buildField(
context,
hintText: 'Your email',
keyboardType: TextInputType.emailAddress,
),
),
),
],
),
Style.empty(
children: [
const Style(
'block text-sm font-medium text-gray-900 dark:text-white',
child: Text('Message'),
),
Style(
'mt-1 w-full resize-none rounded-lg border-gray-300 focus:border-indigo-500 focus:outline-none dark:border-gray-600 dark:bg-gray-900 dark:text-white',
child: Builder(
builder: (context) =>
_buildField(context, hintText: 'Your message', maxLines: 4, minLines: 4),
),
),
],
),
Style(
'block w-full rounded-lg border border-indigo-600 bg-indigo-600 px-12 py-3 text-sm font-medium text-white transition-colors hover:bg-transparent hover:text-indigo-600 dark:hover:bg-indigo-700 dark:hover:text-white',
child: const Text('Send Message'),
),
],
),
],
),
);
}
}
Widget _buildField(
BuildContext context, {
required String hintText,
TextInputType? keyboardType,
int? maxLines,
int? minLines,
}) {
final isDark = Theme.of(context).brightness == Brightness.dark;
final borderColor = isDark ? tailwindColors['gray']![600]! : tailwindColors['gray']![300]!;
final border = OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(color: borderColor),
);
final baseStyle = Theme.of(context).textTheme.bodyLarge ?? const TextStyle();
return TextFormField(
keyboardType: keyboardType,
maxLines: maxLines,
minLines: minLines,
style: baseStyle.copyWith(
color: isDark ? Colors.white : Colors.black,
letterSpacing: 0,
),
decoration: InputDecoration(
hintText: hintText,
hintStyle: TextStyle(color: tailwindColors['gray']![500], letterSpacing: 0),
isDense: true,
filled: true,
fillColor: isDark ? tailwindColors['gray']![900] : Colors.white,
contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 9),
border: border,
enabledBorder: border,
focusedBorder: border,
),
);
}