Accordion
An expandable/collapsible component for showing and hiding content panels with support for multiple expansion modes
An accordion component that manages expansion state of content panels with min/max constraints.
When to use this
- FAQ sections: Display frequently asked questions with expandable answers
- Content organization: Organize large amounts of content in a compact, scannable format
- Settings panels: Group related settings that can be shown/hidden
- Navigation menus: Create collapsible menu structures with nested content
Basic implementation
Basic implementation
import 'package:flutter/material.dart';
import 'package:remix/remix.dart';
class AccordionExample extends StatefulWidget {
const AccordionExample({super.key});
@override
State<AccordionExample> createState() => _AccordionExampleState();
}
class _AccordionExampleState extends State<AccordionExample> {
final controller = RemixAccordionController<String>(min: 0, max: 1);
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return RemixAccordionGroup(
controller: controller,
child: ColumnBox(
style: FlexBoxStyler().spacing(16),
children: [
RemixAccordion(
value: 'accordion1',
title: 'How do I update my account information?',
leadingIcon: Icons.help_outline,
style: itemStyle,
child: const Text(
'Insert the accordion description here. It would look better as two lines of text.',
),
),
RemixAccordion(
value: 'accordion2',
title: 'What payment methods are accepted?',
leadingIcon: Icons.help_outline,
style: itemStyle,
child: const Text(
'Major credit and debit cards like Visa, MasterCard, and American Express, as well as digital payment options like PayPal and Apple Pay.'),
),
RemixAccordion(
value: 'accordion3',
title: 'How can I track my order?',
leadingIcon: Icons.help_outline,
style: itemStyle,
child: const Text(
'You can track your order status in the "My Orders" section of your account.'),
),
],
),
);
}
RemixAccordionStyle<String> get itemStyle {
return RemixAccordionStyle<String>()
.content(BoxStyler().paddingX(16).paddingTop(8))
.wrapClipRRect(borderRadius: BorderRadius.circular(8))
.paddingX(16)
.paddingY(14)
.borderRounded(8)
.onHovered(RemixAccordionStyle<String>().color(Colors.grey.shade100))
.decoration(
BoxDecorationMix(
color: Colors.white,
border: BoxBorderMix.all(
BorderSideMix().color(Colors.grey.shade300).width(1),
),
borderRadius: BorderRadiusMix.circular(8),
),
)
.trigger(
FlexBoxStyler()
.direction(Axis.horizontal)
.mainAxisAlignment(MainAxisAlignment.spaceBetween)
.spacing(12),
)
.leadingIcon(IconStyler().color(Colors.grey.shade700).size(20))
.title(
TextStyler()
.color(Colors.grey.shade900)
.fontWeight(FontWeight.w500)
.fontSize(14),
)
.trailingIcon(IconStyler().color(Colors.grey.shade700).size(20));
}
}
Fortal styles
Remix includes Fortal-themed style helpers for this component:
Fortal base style
import 'package:flutter/material.dart';
import 'package:remix/remix.dart';
class FortalAccordionExample extends StatefulWidget {
const FortalAccordionExample({super.key});
@override
State<FortalAccordionExample> createState() => _FortalAccordionExampleState();
}
class _FortalAccordionExampleState extends State<FortalAccordionExample> {
final controller = RemixAccordionController<String>();
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return RemixAccordionGroup(
controller: controller,
child: Column(
children: [
RemixAccordion(
value: 'item1',
title: 'First Item',
style: FortalAccordionStyle.base(),
child: Text('First content'),
),
RemixAccordion(
value: 'item2',
title: 'Second Item',
style: FortalAccordionStyle.base(),
child: Text('Second content'),
),
],
),
);
}
}
See the FortalAccordionStyle source code for all available options.
Constructor
Constructor
// Accordion Group
const RemixAccordionGroup({
Key? key,
required Widget child,
required RemixAccordionController<T> controller,
List<T> initialExpandedValues = const [],
})
// Accordion Item
const RemixAccordion({
Key? key,
required T value,
required Widget child,
String? title,
IconData? leadingIcon,
IconData? trailingIcon,
NakedAccordionTriggerBuilder<T>? builder,
bool enabled = true,
MouseCursor mouseCursor = SystemMouseCursors.click,
bool enableFeedback = true,
bool autofocus = false,
FocusNode? focusNode,
ValueChanged<bool>? onFocusChange,
ValueChanged<bool>? onHoverChange,
ValueChanged<bool>? onPressChange,
String? semanticLabel,
RemixAccordionStyle style = const RemixAccordionStyle.create(),
Widget Function(Widget, Animation<double>) transitionBuilder = defaultAccordionTransitionBuilder,
})

