logo

Aki UI

アキ ウイ

Type Writer

タイプライター

Lines that type themselves out, pause, erase and hand over to the next one. The keystroke delay is deliberately uneven — a tenth of the presses hesitate, a tenth run ahead and the rest scatter around the nominal speed — because perfectly regular timing is the single thing that makes this effect read as a machine rather than a hand. The whole loop is one setTimeout chain driven by refs, so a re-render never types a character twice, and the sequences are held in a ref so passing a fresh array literal does not restart a word halfway through. Adapted from Kokonut UI under the MIT licence.

Installation

Install the following dependencies:1

npm install framer-motion

Copy and paste the following code into a new component file:2

"use client"

/**
* Adapted for Aki UI from Kokonut UI's Typewriter.
* Original author: @dorianbaffier — https://kokonutui.com
* Copyright (c) 2025 kokonutUI, MIT License.
* https://github.com/kokonut-labs/kokonutui
*
* Reworked here onto the local palette, with shadcn primitives and
* class-variance-authority removed and motion/react swapped for framer-motion.

How to use it3

"use client"

import { TypeWriter } from "@/components/ui/type-writer"

export default function Page() {
return (
<TypeWriter
sequences={[
{ text: "Ship the component.", deleteAfter: true },
{ text: "Then write the page.", deleteAfter: true },

Props

TypeWriter

NameDefaultDescription
sequences

{ text: string, deleteAfter?: boolean, pauseAfter?: number }[]

Lines to type, in order

typingSpeed50

number

Nominal milliseconds per keystroke

deleteSpeed30

number

Milliseconds per character while erasing

startDelay200

number

Milliseconds before the first keystroke

pauseBeforeDelete1000

number

Milliseconds a finished line is held, unless the line sets pauseAfter

loopDelay1000

number

Milliseconds between the last line and the first

autoLooptrue

boolean

Start over after the last line

naturalVariancetrue

boolean

Scatter the keystroke timing instead of holding it constant

darkfalse

boolean

Render the dark palette