Blocks / messaging
Comment row
Shows one comment under a post: avatar, name, age and text, replies indented on a single level, posting or failed with retry, and its actions as links.
Import
Comment row is part of Fliin Pro. With a license key, sign in once with fliin login, then add it in a Flutter app where fliin init has run:
fliin login
fliin add comment-rowAlso installs: core, avatar, button, icons, link-button, chip
Examples
Comment
A comment under a post, with its author, time and a Reply action.
import 'package:your_app/ui/fliin/components/comment_row/fl_comment_row.dart';
import 'package:flutter/widgets.dart';
class CommentRowCommentExample extends StatelessWidget {
const CommentRowCommentExample({super.key});
@override
Widget build(BuildContext context) {
return FlCommentRow(
author: 'Hugo Martin',
initials: 'HM',
time: '12 min',
text: 'Lovely light, was it taken from the balcony?',
actions: [FlCommentAction(label: 'Reply', onPressed: () {})],
);
}
}Reply
reply: true indents an answer under the comment it replies to.
import 'package:your_app/ui/fliin/components/comment_row/fl_comment_row.dart';
import 'package:flutter/widgets.dart';
class CommentRowReplyExample extends StatelessWidget {
const CommentRowReplyExample({super.key});
@override
Widget build(BuildContext context) {
return FlCommentRow(
author: 'Leah Bernard',
initials: 'LB',
time: '8 min',
text: 'Yes, around seven.',
reply: true,
actions: [FlCommentAction(label: 'Reply', onPressed: () {})],
);
}
}Sending
The user's own comment while it posts: FlCommentStatus.sending dims it and statusLabel says what is happening.
import 'package:your_app/ui/fliin/components/comment_row/fl_comment_row.dart';
import 'package:flutter/widgets.dart';
class CommentRowSendingExample extends StatelessWidget {
const CommentRowSendingExample({super.key});
@override
Widget build(BuildContext context) {
return const FlCommentRow(
author: 'You',
initials: 'CD',
time: 'Now',
text: 'Love the framing.',
status: FlCommentStatus.sending,
statusLabel: 'Posting…',
);
}
}Failed
A comment that could not be posted: FlCommentStatus.failed marks it, and its actions offer to try again or delete it.
import 'package:your_app/ui/fliin/components/comment_row/fl_comment_row.dart';
import 'package:flutter/widgets.dart';
class CommentRowFailedExample extends StatelessWidget {
const CommentRowFailedExample({super.key});
@override
Widget build(BuildContext context) {
return FlCommentRow(
author: 'You',
initials: 'CD',
time: 'Now',
text: 'Shall we go back on Saturday?',
status: FlCommentStatus.failed,
statusLabel: 'Not posted',
actions: [
FlCommentAction(label: 'Try again', onPressed: () {}),
FlCommentAction(label: 'Delete', onPressed: () {}),
],
);
}
}Liked
Comments as social apps show them: the author's photo, authorBadge after the name of the post's author, and a heart with its count at the end of the row (likeLabel, likes, liked, onLike).
import 'package:your_app/ui/fliin/components/comment_row/fl_comment_row.dart';
import 'package:your_app/ui/fliin/components/link_button/fl_link_button.dart';
import 'package:your_app/ui/fliin/core/fliin.dart';
import 'package:flutter/widgets.dart';
class CommentRowLikedExample extends StatefulWidget {
const CommentRowLikedExample({super.key});
@override
State<CommentRowLikedExample> createState() => _CommentRowLikedExampleState();
}
class _CommentRowLikedExampleState extends State<CommentRowLikedExample> {
var _liked = true;
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
spacing: FlScope.of(context).space.lg,
children: [
FlCommentRow(
author: 'John Doe',
initials: 'JD',
avatar: const AssetImage('images/people/2.jpg'),
time: '12 min',
text: 'Was this taken from the balcony?',
likeLabel: 'Like',
likes: _liked ? '24' : '23',
liked: _liked,
onLike: () => setState(() => _liked = !_liked),
actions: [FlCommentAction(label: 'Reply', tone: FlLinkButtonTone.muted, onPressed: () {})],
),
FlCommentRow(
author: 'Kate Wilson',
initials: 'KW',
avatar: const AssetImage('images/people/1.jpg'),
authorBadge: 'Author',
time: '8 min',
text: 'Yes, around seven in the morning.',
reply: true,
replyLabel: 'Reply to John Doe',
likeLabel: 'Like',
likes: '3',
onLike: () {},
),
],
);
}
}Usage
The code the reference images render:
final example = ColoredBox(
color: FlScope.of(context).colors.surface,
child: SingleChildScrollView(
padding: EdgeInsetsDirectional.all(FlScope.of(context).space.lg),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
spacing: FlScope.of(context).space.lg,
children: [
FlCommentRow(
author: 'Leah Bernard',
initials: 'LB',
time: (variant.dir == TextDirection.rtl ? "12 د" : "12 min"),
text: (variant.dir == TextDirection.rtl
? "ضوء رائع، هل التُقطت من الشرفة؟"
: "Beautiful light, was it taken from the balcony?"),
actions: [
FlCommentAction(
label: (variant.dir == TextDirection.rtl ? "رد" : "Reply"),
tone: FlLinkButtonTone.muted,
onPressed: () {},
),
],
),
FlCommentRow(
author: 'Hugo Martin',
initials: 'HM',
avatarColor: FlAvatarColor.success,
time: (variant.dir == TextDirection.rtl ? "8 د" : "8 min"),
text: (variant.dir == TextDirection.rtl
? "نعم، نحو السابعة."
: "Yes, around seven."),
reply: true,
actions: [
FlCommentAction(
label: (variant.dir == TextDirection.rtl ? "رد" : "Reply"),
tone: FlLinkButtonTone.muted,
onPressed: () {},
),
],
),
FlCommentRow(
author: (variant.dir == TextDirection.rtl ? "أنت" : "You"),
initials: 'CD',
avatarColor: FlAvatarColor.accent,
avatarVariant: FlAvatarVariant.soft,
time: (variant.dir == TextDirection.rtl ? "الآن" : "Now"),
text: (variant.dir == TextDirection.rtl
? "أحب هذا الإطار."
: "Love the framing."),
status: FlCommentStatus.sending,
statusLabel: (variant.dir == TextDirection.rtl
? "جارٍ النشر…"
: "Posting…"),
),
FlCommentRow(
author: (variant.dir == TextDirection.rtl ? "أنت" : "You"),
initials: 'CD',
avatarColor: FlAvatarColor.accent,
avatarVariant: FlAvatarVariant.soft,
time: (variant.dir == TextDirection.rtl ? "الآن" : "Now"),
text: (variant.dir == TextDirection.rtl
? "هل نعود يوم السبت؟"
: "Shall we go back on Saturday?"),
reply: true,
status: FlCommentStatus.failed,
statusLabel: (variant.dir == TextDirection.rtl
? "لم يُنشر"
: "Not posted"),
actions: [
FlCommentAction(
label: (variant.dir == TextDirection.rtl
? "أعد المحاولة"
: "Try again"),
onPressed: () {},
),
FlCommentAction(
label: (variant.dir == TextDirection.rtl ? "حذف" : "Delete"),
tone: FlLinkButtonTone.danger,
onPressed: () {},
),
],
),
],
),
),
);API
FlCommentStatus: enum {sending, failed}
FlCommentStatus.sending: static final FlCommentStatus
FlCommentStatus.failed: static final FlCommentStatus
FlCommentAction: final class
FlCommentAction.new: const new({required String label, required VoidCallback onPressed, String? semanticLabel, FlLinkButtonTone tone})
FlCommentAction.label: get String
FlCommentAction.semanticLabel: get String?
FlCommentAction.onPressed: get VoidCallback
FlCommentAction.tone: get FlLinkButtonTone
FlCommentRow: class extends StatelessWidget
FlCommentRow.new: const new({super.key, required String author, required String initials, ImageProvider? avatar, FlAvatarColor avatarColor, FlAvatarVariant avatarVariant, required String time, required String text, bool reply, String? replyLabel, FlCommentStatus? status, String? statusLabel, List<FlCommentAction> actions, String? authorBadge, String? likeLabel, String likes, bool liked, VoidCallback? onLike})
FlCommentRow.author: get String
FlCommentRow.initials: get String
FlCommentRow.avatar: get ImageProvider?
FlCommentRow.avatarColor: get FlAvatarColor
FlCommentRow.avatarVariant: get FlAvatarVariant
FlCommentRow.time: get String
FlCommentRow.text: get String
FlCommentRow.reply: get bool
FlCommentRow.replyLabel: get String?
FlCommentRow.status: get FlCommentStatus?
FlCommentRow.statusLabel: get String?
FlCommentRow.actions: get List<FlCommentAction>
FlCommentRow.authorBadge: get String?
FlCommentRow.likeLabel: get String?
FlCommentRow.likes: get String
FlCommentRow.liked: get bool
FlCommentRow.onLike: get VoidCallback?
FlCommentRow.build: Widget(BuildContext context)Reference renders
The 16 images published with version 0.2.4, rendered by the shared harness on macOS with Flutter 3.47.7. fliin verify comment-row compares your copy to them.
















Use it to
- show a single comment under a post with its author and time
- show replies indented under a comment
- show that a comment is posting or failed to post
- offer reply and delete links under a comment
- give a failed comment a retry action
- Not for
- a message in a private discussion: use a message bubble (message-bubble)
- a whole post with its images: use a post card (post-card)
- States