Stackbits
Texts > Dotted Text

⚪️ Dotted Text

Create stunning dot matrix animations with this interactive React component powered by Framer Motion. Easily render letters and numbers in a retro pixel-style grid, perfect for eye-catching UI designs, loading screens, or creative typography effects. Fully customizable and optimized for smooth performance in modern web applications

Preview

Follow below steps 👇🏻

Install dependencies

1
npm i framer-motion

Component

Create a file dotted-text.tsx in your components folder and paste this code

1
'use client';
2
3
import { motion } from 'framer-motion';
4
5
// Define the dot matrix for each character
6
const charMatrix: Record<string, number[][]> = {
7
A: [
8
[0, 1, 1, 0],
9
[1, 0, 0, 1],
10
[1, 1, 1, 1],
11
[1, 0, 0, 1],
12
[1, 0, 0, 1]
13
],
14
B: [
15
[1, 1, 1, 0],
16
[1, 0, 0, 1],
17
[1, 1, 1, 0],
18
[1, 0, 0, 1],
19
[1, 1, 1, 0]
20
],
21
C: [
22
[0, 1, 1, 0],
23
[1, 0, 0, 1],
24
[1, 0, 0, 0],
25
[1, 0, 0, 1],
26
[0, 1, 1, 0]
27
],
28
D: [
29
[1, 1, 1, 0],
30
[1, 0, 0, 1],
31
[1, 0, 0, 1],
32
[1, 0, 0, 1],
33
[1, 1, 1, 0]
34
],
35
E: [
36
[1, 1, 1, 1],
37
[1, 0, 0, 0],
38
[1, 1, 1, 0],
39
[1, 0, 0, 0],
40
[1, 1, 1, 1]
41
],
42
F: [
43
[1, 1, 1, 1],
44
[1, 0, 0, 0],
45
[1, 1, 1, 0],
46
[1, 0, 0, 0],
47
[1, 0, 0, 0]
48
],
49
G: [
50
[0, 1, 1, 0],
51
[1, 0, 0, 1],
52
[1, 0, 0, 0],
53
[1, 0, 1, 1],
54
[0, 1, 1, 1]
55
],
56
H: [
57
[1, 0, 0, 1],
58
[1, 0, 0, 1],
59
[1, 1, 1, 1],
60
[1, 0, 0, 1],
61
[1, 0, 0, 1]
62
],
63
I: [
64
[1, 1, 1],
65
[0, 1, 0],
66
[0, 1, 0],
67
[0, 1, 0],
68
[1, 1, 1]
69
],
70
J: [
71
[0, 0, 1, 1],
72
[0, 0, 0, 1],
73
[0, 0, 0, 1],
74
[1, 0, 0, 1],
75
[0, 1, 1, 0]
76
],
77
K: [
78
[1, 0, 0, 1],
79
[1, 0, 1, 0],
80
[1, 1, 0, 0],
81
[1, 0, 1, 0],
82
[1, 0, 0, 1]
83
],
84
L: [
85
[1, 0, 0, 0],
86
[1, 0, 0, 0],
87
[1, 0, 0, 0],
88
[1, 0, 0, 0],
89
[1, 1, 1, 1]
90
],
91
M: [
92
[1, 0, 0, 0, 1],
93
[1, 1, 0, 1, 1],
94
[1, 0, 1, 0, 1],
95
[1, 0, 0, 0, 1],
96
[1, 0, 0, 0, 1]
97
],
98
N: [
99
[1, 0, 0, 1],
100
[1, 1, 0, 1],
101
[1, 0, 1, 1],
102
[1, 0, 0, 1],
103
[1, 0, 0, 1]
104
],
105
O: [
106
[0, 1, 1, 0],
107
[1, 0, 0, 1],
108
[1, 0, 0, 1],
109
[1, 0, 0, 1],
110
[0, 1, 1, 0]
111
],
112
P: [
113
[1, 1, 1, 0],
114
[1, 0, 0, 1],
115
[1, 1, 1, 0],
116
[1, 0, 0, 0],
117
[1, 0, 0, 0]
118
],
119
Q: [
120
[0, 1, 1, 0],
121
[1, 0, 0, 1],
122
[1, 0, 0, 1],
123
[1, 0, 1, 1],
124
[0, 1, 1, 1]
125
],
126
R: [
127
[1, 1, 1, 0],
128
[1, 0, 0, 1],
129
[1, 1, 1, 0],
130
[1, 0, 1, 0],
131
[1, 0, 0, 1]
132
],
133
S: [
134
[0, 1, 1, 1],
135
[1, 0, 0, 0],
136
[0, 1, 1, 0],
137
[0, 0, 0, 1],
138
[1, 1, 1, 0]
139
],
140
T: [
141
[1, 1, 1, 1, 1],
142
[0, 0, 1, 0, 0],
143
[0, 0, 1, 0, 0],
144
[0, 0, 1, 0, 0],
145
[0, 0, 1, 0, 0]
146
],
147
U: [
148
[1, 0, 0, 1],
149
[1, 0, 0, 1],
150
[1, 0, 0, 1],
151
[1, 0, 0, 1],
152
[0, 1, 1, 0]
153
],
154
V: [
155
[1, 0, 0, 1],
156
[1, 0, 0, 1],
157
[1, 0, 0, 1],
158
[0, 1, 1, 0],
159
[0, 0, 1, 0]
160
],
161
W: [
162
[1, 0, 0, 0, 1],
163
[1, 0, 0, 0, 1],
164
[1, 0, 1, 0, 1],
165
[1, 1, 0, 1, 1],
166
[1, 0, 0, 0, 1]
167
],
168
X: [
169
[1, 0, 0, 1],
170
[0, 1, 1, 0],
171
[0, 0, 0, 0],
172
[0, 1, 1, 0],
173
[1, 0, 0, 1]
174
],
175
Y: [
176
[1, 0, 0, 1],
177
[0, 1, 1, 0],
178
[0, 0, 1, 0],
179
[0, 0, 1, 0],
180
[0, 0, 1, 0]
181
],
182
Z: [
183
[1, 1, 1, 1],
184
[0, 0, 0, 1],
185
[0, 0, 1, 0],
186
[0, 1, 0, 0],
187
[1, 1, 1, 1]
188
],
189
'0': [
190
[0, 1, 1, 0],
191
[1, 0, 0, 1],
192
[1, 0, 0, 1],
193
[1, 0, 0, 1],
194
[0, 1, 1, 0]
195
],
196
'1': [
197
[0, 1, 0],
198
[1, 1, 0],
199
[0, 1, 0],
200
[0, 1, 0],
201
[1, 1, 1]
202
],
203
'2': [
204
[0, 1, 1, 0],
205
[1, 0, 0, 1],
206
[0, 0, 1, 0],
207
[0, 1, 0, 0],
208
[1, 1, 1, 1]
209
],
210
'3': [
211
[1, 1, 1, 0],
212
[0, 0, 0, 1],
213
[0, 1, 1, 0],
214
[0, 0, 0, 1],
215
[1, 1, 1, 0]
216
],
217
'4': [
218
[0, 0, 1, 1],
219
[0, 1, 0, 1],
220
[1, 0, 0, 1],
221
[1, 1, 1, 1],
222
[0, 0, 0, 1]
223
],
224
'5': [
225
[1, 1, 1, 1],
226
[1, 0, 0, 0],
227
[1, 1, 1, 0],
228
[0, 0, 0, 1],
229
[1, 1, 1, 0]
230
],
231
'6': [
232
[0, 1, 1, 0],
233
[1, 0, 0, 0],
234
[1, 1, 1, 0],
235
[1, 0, 0, 1],
236
[0, 1, 1, 0]
237
],
238
'7': [
239
[1, 1, 1, 1],
240
[0, 0, 0, 1],
241
[0, 0, 1, 0],
242
[0, 1, 0, 0],
243
[0, 1, 0, 0]
244
],
245
'8': [
246
[0, 1, 1, 0],
247
[1, 0, 0, 1],
248
[0, 1, 1, 0],
249
[1, 0, 0, 1],
250
[0, 1, 1, 0]
251
],
252
'9': [
253
[0, 1, 1, 0],
254
[1, 0, 0, 1],
255
[0, 1, 1, 1],
256
[0, 0, 0, 1],
257
[0, 1, 1, 0]
258
],
259
'.': [[0], [0], [0], [0], [1]],
260
',': [[0], [0], [0], [1], [1]],
261
'!': [[1], [1], [1], [0], [1]],
262
'?': [
263
[0, 1, 1, 0],
264
[1, 0, 0, 1],
265
[0, 0, 1, 0],
266
[0, 0, 0, 0],
267
[0, 0, 1, 0]
268
],
269
'+': [
270
[0, 0, 0],
271
[0, 1, 0],
272
[1, 1, 1],
273
[0, 1, 0],
274
[0, 0, 0]
275
],
276
'-': [
277
[0, 0, 0],
278
[0, 0, 0],
279
[1, 1, 1],
280
[0, 0, 0],
281
[0, 0, 0]
282
],
283
'*': [
284
[1, 0, 1],
285
[0, 1, 0],
286
[1, 0, 1],
287
[0, 0, 0],
288
[0, 0, 0]
289
],
290
'/': [
291
[0, 0, 0, 1],
292
[0, 0, 1, 0],
293
[0, 1, 0, 0],
294
[1, 0, 0, 0],
295
[0, 0, 0, 0]
296
],
297
'=': [
298
[0, 0, 0],
299
[1, 1, 1],
300
[0, 0, 0],
301
[1, 1, 1],
302
[0, 0, 0]
303
],
304
' ': [
305
[0, 0],
306
[0, 0],
307
[0, 0],
308
[0, 0],
309
[0, 0]
310
]
311
};
312
313
// Default matrix for unknown characters
314
const defaultMatrix = [
315
[1, 1],
316
[1, 1],
317
[1, 1],
318
[1, 1],
319
[1, 1]
320
];
321
322
interface DottedTextProps {
323
text: string;
324
color?: string;
325
backgroundColor?: string;
326
size?: number;
327
spacing?: number;
328
animationDelay?: number;
329
animationColors?: string[];
330
animationDuration?: number;
331
shadowIntensity?: number;
332
}
333
334
const DottedText: React.FC<DottedTextProps> = ({
335
text,
336
size = 10,
337
spacing = 2,
338
animationDelay = 0.3,
339
animationColors = [
340
'#1A0B33', // Deeper purple (twilight)
341
'#5D2E8C', // Purple
342
'#F25C54', // Coral/orange
343
'#F7B267', // Golden orange
344
'#FFD166', // Amber/gold
345
'#FFEDDF', // Soft light
346
'#F7B267', // Golden orange
347
'#F25C54', // Coral/orange
348
'#5D2E8C', // Purple
349
'#1A0B33' // Deeper purple (twilight)
350
],
351
animationDuration = 4,
352
shadowIntensity = 15
353
}) => {
354
const renderDot = (
355
filled: boolean,
356
x: number,
357
y: number,
358
animationIndex: number,
359
repeatDelay: number
360
) => {
361
const dotSize = `${size}px`;
362
363
if (!filled) {
364
return (
365
<div
366
key={`${x}-${y}`}
367
style={{
368
width: dotSize,
369
height: dotSize,
370
margin: `${spacing}px`,
371
display: 'inline-block'
372
}}
373
/>
374
);
375
}
376
377
return (
378
<motion.div
379
key={`${x}-${y}`}
380
style={{
381
width: dotSize,
382
height: dotSize,
383
borderRadius: '50%',
384
border: '1px solid #FFFFFF47',
385
margin: `${spacing}px`,
386
display: 'inline-block',
387
backgroundColor: animationColors[0]
388
}}
389
initial={{
390
backgroundColor: animationColors[0],
391
boxShadow: 'none'
392
}}
393
animate={{
394
backgroundColor: animationColors,
395
boxShadow: [
396
'none',
397
'none',
398
`0 0 ${shadowIntensity / 2.1}px 0 ${animationColors[2]}`,
399
`0 0 ${shadowIntensity / 2}px 0 ${animationColors[3]}`,
400
`0 0 ${shadowIntensity}px 0 ${animationColors[4]}`,
401
`0 0 ${shadowIntensity}px 0 ${animationColors[5]}`,
402
`0 0 ${shadowIntensity / 2}px 0 ${animationColors[6]}`,
403
`0 0 ${shadowIntensity / 2.1}px 0 ${animationColors[7]}`,
404
'none',
405
'none'
406
]
407
}}
408
transition={{
409
duration: animationDuration,
410
delay: animationIndex * animationDelay,
411
repeat: Infinity,
412
repeatType: 'reverse',
413
repeatDelay: repeatDelay,
414
ease: 'easeInOut'
415
}}
416
/>
417
);
418
};
419
420
const renderCharacter = (char: string, charIndex: number, totalChars: number) => {
421
const upperChar = char.toUpperCase();
422
const matrix = charMatrix[upperChar] || defaultMatrix;
423
424
return (
425
<div
426
key={`${charIndex}`}
427
style={{
428
display: 'inline-block',
429
marginRight: `${spacing * 3}px`,
430
verticalAlign: 'top'
431
}}
432
>
433
{matrix.map((row, rowIndex) => (
434
<div key={`${rowIndex}`} style={{ display: 'flex' }}>
435
{row.map((dot, dotColIndex) =>
436
renderDot(
437
dot === 1,
438
charIndex * (matrix[0].length + 2) + dotColIndex,
439
rowIndex,
440
charIndex * 4 + dotColIndex,
441
totalChars * 0.8
442
)
443
)}
444
</div>
445
))}
446
</div>
447
);
448
};
449
450
return (
451
<div className="flex flex-wrap gap-2 relative">
452
{text.split('').map((char, index) => renderCharacter(char, index, text.length))}
453
</div>
454
);
455
};
456
457
export default DottedText;

Usage

1
<DottedText text="LM10" />

⭐️ Got a question or feedback?
Feel free to reach out!