How to decorate text stroke in Flutter? It's like -webkit-text-stroke - CSS
-
Please check the docs: https://docs.flutter.io/ https://docs.flutter.io/flutter/painting/TextStyle-class.html – Arnold Parge Sep 03 '18 at 12:17
-
1I confirmed the doc, but there was no description about what I wanted to do. Is there a way to do it without using TextStyle? – granoeste Sep 04 '18 at 01:01
-
I dont understand why you dont want to use TextStyle, if that give the desired output? – Arnold Parge Sep 04 '18 at 06:56
-
TextDecoration has lineThrough, overline and underline. But, it does not have text-stroke. Is it right? I want decorate text with border like [text-stroke](https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-text-stroke) of css. Can it with TextStyle? – granoeste Sep 05 '18 at 02:25
-
here is the simple solution [solution](https://stackoverflow.com/a/64549730/11914296) – Luqman Tuke Jun 11 '22 at 11:29
7 Answers
Stroke has been possible without workarounds since the addition of foreground paints in TextStyle. An explicit example of stroke under fill bordered text has been added in the TextStyle documentation: https://master-api.flutter.dev/flutter/painting/TextStyle-class.html#painting.TextStyle.6
This example is reproduced here:
Stack(
children: <Widget>[
// Stroked text as border.
Text(
'Greetings, planet!',
style: TextStyle(
fontSize: 40,
foreground: Paint()
..style = PaintingStyle.stroke
..strokeWidth = 6
..color = Colors.blue[700],
),
),
// Solid text as fill.
Text(
'Greetings, planet!',
style: TextStyle(
fontSize: 40,
color: Colors.grey[300],
),
),
],
)
Stroke by itself is possible by removing the Stack and just using the first stroke Text widget by itself. The stroke/fill order can also be adjusted by swapping the first and second Text widget.

- 2,984
- 3
- 10
- 7
-
-
Unfortunately, emojis are rendered as bitmaps and do not use stroke. – Gary Qian Sep 28 '21 at 00:33
-
This will only work in areas that can accept a `Stack()`. If you are working with something which requires a `Text()` widget, then see the below _shadow_ method. For example, if you are labeling a pie chart, and your text flows across multiple colors, and the chart only accepts a text and a `TextStyle()`. – Matthew Rideout Dec 08 '22 at 22:42
-
4This no longer works on iOS since Flutter upgraded to use Impeller rendering engine. The shadows solution is fine. – Apetroaei Andrei Jun 22 '23 at 15:39
I was also looking for this, wasn't able to find it. But I did find a workaround using 4 shadows in the TextStyle:
Text("Border test",
style: TextStyle(
inherit: true,
fontSize: 48.0,
color: Colors.pink,
shadows: [
Shadow( // bottomLeft
offset: Offset(-1.5, -1.5),
color: Colors.white
),
Shadow( // bottomRight
offset: Offset(1.5, -1.5),
color: Colors.white
),
Shadow( // topRight
offset: Offset(1.5, 1.5),
color: Colors.white
),
Shadow( // topLeft
offset: Offset(-1.5, 1.5),
color: Colors.white
),
]
),
);
I also opened an Issue on GitHub: https://github.com/flutter/flutter/issues/24108

- 3,578
- 2
- 23
- 33
-
Stroke is possible to do without this workaround :) I posted how to achieve this in my answer. – Gary Qian Jul 26 '19 at 22:18
-
1As of Flutter 2.5.1 (stable) for web target this solution works in both the HTML and CanvasKit renderer whereas the PaintingStyle.stroke method doesn't work in either. Note that after adding it to a TextStyle you have to restart (not just Hot Reload) to see it. – Pat9RB Oct 18 '21 at 18:21
-
1
Inspired by this article, to achieve the effect, I prefer to use a technique that mixes two Text widgets and TextStype.foreground property with custom Paint():
class StrokeText extends StatelessWidget {
final String text;
final double fontSize;
final FontWeight fontWeight;
final Color color;
final Color strokeColor;
final double strokeWidth;
const StrokeText(
this.text, {
Key key,
this.fontSize,
this.fontWeight,
this.color,
this.strokeColor,
this.strokeWidth,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Stack(
children: [
Text(
text,
style: TextStyle(
fontSize: fontSize,
fontWeight: fontWeight,
foreground: Paint()..color = color,
),
),
Text(
text,
style: TextStyle(
fontSize: fontSize,
fontWeight: fontWeight,
foreground: Paint()
..strokeWidth = strokeWidth
..color = strokeColor
..style = PaintingStyle.stroke,
),
),
],
);
}
}

- 386
- 4
- 8
-
[check this out](https://tutorsvilla.blogspot.com/2019/06/how-to-add-text-border-or-text-stroke-flutter.html) courtesy of your code. – tewshi Jun 13 '19 at 15:45
If you prefer the shadows method, you can configure the stroke width using :
/// Outlines a text using shadows.
static List<Shadow> outlinedText({double strokeWidth = 2, Color strokeColor = Colors.black, int precision = 5}) {
Set<Shadow> result = HashSet();
for (int x = 1; x < strokeWidth + precision; x++) {
for(int y = 1; y < strokeWidth + precision; y++) {
double offsetX = x.toDouble();
double offsetY = y.toDouble();
result.add(Shadow(offset: Offset(-strokeWidth / offsetX, -strokeWidth / offsetY), color: strokeColor));
result.add(Shadow(offset: Offset(-strokeWidth / offsetX, strokeWidth / offsetY), color: strokeColor));
result.add(Shadow(offset: Offset(strokeWidth / offsetX, -strokeWidth / offsetY), color: strokeColor));
result.add(Shadow(offset: Offset(strokeWidth / offsetX, strokeWidth / offsetY), color: strokeColor));
}
}
return result.toList();
}
Use it like this :
Text(
'My text',
style: TextStyle(shadows: outlinedText(strokeColor: Colors.blue)),
);

- 1,429
- 1
- 16
- 31
Inspired by @Gary Qian's answer
Widget textWithStroke({String text, String fontFamily, double fontSize: 12, double strokeWidth: 1, Color textColor: Colors.white, Color strokeColor: Colors.black}) {
return Stack(
children: <Widget>[
Text(
text,
style: TextStyle(
fontSize: fontSize,
fontFamily: fontFamily,
foreground: Paint()
..style = PaintingStyle.stroke
..strokeWidth = strokeWidth
..color = strokeColor,
),
),
Text(text, style: TextStyle(fontFamily: fontFamily, fontSize: fontSize, color: textColor)),
],
);
}

- 318
- 4
- 10
This is @Aleh's answer migrated to null-safety and with some more flexibility. Simply paste this inside a new file, and use freely.
import 'package:flutter/widgets.dart';
/// Places a stroke around text to make it appear outlined
///
/// Adapted from https://stackoverflow.com/a/55559435/11846040
class OutlinedText extends StatelessWidget {
/// Text to display
final String text;
/// Original text style (if you weren't outlining)
///
/// Do not specify `color` inside this: use [textColor] instead.
final TextStyle style;
/// Text color
final Color textColor;
/// Outline stroke color
final Color strokeColor;
/// Outline stroke width
final double strokeWidth;
/// Places a stroke around text to make it appear outlined
///
/// Adapted from https://stackoverflow.com/a/55559435/11846040
const OutlinedText(
this.text, {
Key? key,
this.style = const TextStyle(),
required this.textColor,
required this.strokeColor,
required this.strokeWidth,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Stack(
children: [
Text(
text,
style: style.copyWith(foreground: Paint()..color = textColor),
),
Text(
text,
style: style.copyWith(
foreground: Paint()
..strokeWidth = strokeWidth
..color = strokeColor
..style = PaintingStyle.stroke,
),
),
],
);
}
}

- 1,151
- 10
- 26
I created a package using the same logic shared here.
I also make it possible to add multiple strokes at once.

- 1,100
- 1
- 14
- 14