Custom widgets guide
Learn how to create and use custom Flutter widgets in SuperDeck presentations
Custom widgets guide
Render custom Flutter widgets from Markdown. Register widget factories in DeckOptions.widgets, then use them in slides.md.
Markdown syntax
Two equivalent forms:
- Shorthand (recommended) -
@twitter { ... } - Explicit -
@widget { name: "twitter" ... }
All properties pass to your WidgetFactory as a Map<String, Object?>.
Simple: plain function
import 'package:flutter/widgets.dart';
Widget twitterWidget(Map<String, Object?> args) {
final username = args['username'] as String? ?? '';
final tweetId = args['tweetId'] as String? ?? '';
return Text('Twitter: @$username ($tweetId)');
}
Recommended: StatelessWidget with typed args
Parse and validate in the constructor. Import package:superdeck_core/superdeck_core.dart when you want to use Ack for schema validation.
import 'package:flutter/widgets.dart';
import 'package:superdeck/superdeck.dart';
import 'package:superdeck_core/superdeck_core.dart';
class TwitterArgs {
const TwitterArgs({required this.username, required this.tweetId});
final String username;
final String tweetId;
static final schema = Ack.object({
'username': Ack.string().notEmpty(),
'tweetId': Ack.string().notEmpty(),
});
static TwitterArgs parse(Map<String, Object?> map) {
schema.parse(map);
return TwitterArgs(
username: map['username'] as String,
tweetId: map['tweetId'] as String,
);
}
}
class TwitterWidget extends StatelessWidget {
final TwitterArgs data;
TwitterWidget(Map<String, Object?> args, {super.key})
: data = TwitterArgs.parse(args);
@override
Widget build(BuildContext context) {
return Text('Twitter: @${data.username} (${data.tweetId})');
}
}
Register widgets in DeckOptions
import 'package:flutter/widgets.dart';
import 'package:superdeck/superdeck.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await SuperDeckApp.initialize();
runApp(
SuperDeckApp(
options: DeckOptions(
widgets: {
'twitter': TwitterWidget.new,
},
),
),
);
}
Use widgets in slides.md
Shorthand:
@twitter {
username: "flutterdev"
tweetId: "1234567890"
}
Explicit:
@widget {
name: "twitter"
username: "flutterdev"
tweetId: "1234567890"
}
Slide context
SlideConfiguration.of(context) exposes the slide index, options, and
metadata if your widget needs them:
class TwitterWidget extends StatelessWidget {
final TwitterArgs data;
TwitterWidget(Map<String, Object?> args, {super.key})
: data = TwitterArgs.parse(args);
@override
Widget build(BuildContext context) {
final slide = SlideConfiguration.of(context);
return Text('Slide ${slide.slideIndex + 1}: @${data.username}');
}
}
For sizing your widget to the available block area, use Flutter's
LayoutBuilder — it gives you the parent's constraints without any
SuperDeck-specific API:
Widget twitterWidget(Map<String, Object?> args) {
final username = args['username'] as String? ?? '';
return LayoutBuilder(
builder: (context, constraints) => SizedBox(
width: constraints.maxWidth,
child: Text('@$username'),
),
);
}