Receipt
The order recap that comes out of a printer.
Documentation
-
Copy to Webflow
Add Geist and Geist Mono to your site's fonts (Site settings, Fonts, Google Fonts) before pasting: Webflow removes any font your site has not installed. -
Add custom CSS
Custom CSS in WebflowThis CSS already ships inside the Webflow embed, so a pasted section needs nothing added. Paste it yourself, in the page or the site custom code, only if the effect runs on several pages. The tutorial explains where.
See the tutorialBefore the script runs a ticket keeps its room but is not seen, so it never shows printed and then prints. It shows by itself after four seconds if the script never comes, and at once without JavaScript, through the noscript line the paste carries inside its Embed. The width, the padding and the type of the paper are the page's own; leave its foot blank, 1.5em or more, for the teeth. A torn ticket falls outside its block: the section around it takesoverflow: clipwhen it sits near the end of the page. -
Add custom JS
Custom JavaScript in WebflowThis script already ships inside the Webflow embed, settings block included. You paste it yourself, before the closing body tag of the page or the site custom code, only when the effect has to run on several pages, and the tutorial says how to choose.
See the tutorial -
Use it on your own elements
How to add a custom attribute in WebflowA custom attribute is a pair, a name and a value, typed in the Settings panel of the element you selected, under Custom attributes. The name is what the script looks for, the value is what it reads. The tutorial shows the panel.
See the tutorialCustom attributesSelect the element on the canvas and open the Settings panel. Under Custom attributes, add a pair: the name on the left, the value on the right.Custom attribute What it does data-receipt Marks the block that holds the ticket: the slot is laid over its top and the paper comes out under it. It takes no value: leave the value field empty. The settings go on this block. The paper is the block marked data-receipt-ticket inside it. data-receipt-ticket Marks the paper, a child of the block: every child of the paper is one line of the ticket, in the order it reads. It takes no value. Without it the engine takes the first child of the block. [ Optional ] data-receipt-row On a line that holds a label, then an amount: the two go to the two ends and a dotted leader is drawn between them. It takes no value. Without it a line is plain text. [ Optional ] data-receipt-amount On the amount of a row: kept on the right, on one line, in tabular figures. It takes no value. [ Optional ] data-receipt-rule On a separator line: the print head rests four times longer on it. It takes no value. [ Optional ] data-receipt-total On the line of the total: fed in one fast run, and read out by a screen reader once the ticket is printed. It takes no value. [ Optional ] data-receipt-code="DM-4471-1009" On an empty box with a height: the engine draws the bars of that string in it, a Code 128 barcode in the colour of the ink. Characters outside plain ASCII are left out. [ Optional ] data-receipt-tear-label="Tear off the receipt" On the block: the name a screen reader gives the grip at the foot of the ticket. Without it the name is Tear off the receipt. [ Optional ] data-receipt-counter On the section of the preview: takes away the room the Webflow Embed would otherwise occupy at its foot. It takes no value, and a section of your own does not need it. [ Optional ] data-receipt-state Written by the engine on the block: idle while only the edge of the paper is out, printing, printed, tearing, falling, or static under reduced motion. Never written by hand; the stylesheet reads it. [ Optional ] SettingsEvery setting is a custom attribute too, added the same way and on the same element. An attribute always wins over the defaults written in the code.Attribute Default What it is data-receipt-paper #f4ece0 Colour of the paper. Options: any CSS colour. Left on its default, the paper keeps the background of its own class, so a Webflow class or a rule of the page decides. The edge the slot keeps after a tear takes the same colour. data-receipt-ink #15100c Colour of the print: the text, the leaders, the bars of a code. Options: any CSS colour. Left on its default with paper, the text keeps the colour of its own class. Setting either one applies both. data-receipt-trigger view What starts the print. Options: view prints when a third of the block is in the window; scroll feeds the paper as the block rises through the window, and never takes it back when the page scrolls up; manual waits for print(). data-receipt-once on Whether the ticket prints only the first time it is seen: on or off. Options: on prints once and leaves the ticket hanging; off takes the ticket back when the block has left the window, and prints it again the next time. data-receipt-speed 16em Paper the printer feeds in a second, any CSS length. data-receipt-step 0.5em Length of one notch of the feed, any CSS length. The paper moves a notch, holds, moves the next. data-receipt-pause 0.09 Rest of the print head after each line, in seconds. A separator keeps it four times as long, a total twice, after a rest of three before its run. data-receipt-sway 1 Swing and flap the hanging paper takes from each notch, 0 to 3. data-receipt-curl 1 Forward curl of the hanging paper, 0 to 3: the foot leans towards the eye. data-receipt-wear 0.5 Thermal flaws, 0 to 1: two pale columns where a dot of the head is tired, and bands where the ink took less. data-receipt-seed 7 Which flaws, and which way the paper swings: any number. Options: the same seed always gives the same ticket; give two tickets of a page two seeds. data-receipt-tear on Whether the printed ticket can be torn off: on or off. Options: on adds a grip over the foot of the ticket, for a pointer, a finger and the keyboard; off leaves the ticket hanging, and its foot selectable. data-receipt-pull 3.4em Travel the paper resists before it rips, any CSS length. data-receipt-again on Whether a new ticket prints after a tear: on or off. Options: on prints the next one half a second after the torn one is gone; off leaves the slot with its edge of paper until print() is called. data-receipt-slot on The slot the paper comes out of: on or off. Options: on draws a dark bezel, a slit and a lip over the top of the block, a little wider than the paper; off draws nothing, and the paper comes out of the top edge of the block, under whatever the page puts there.
Two files, no build step.
It runs in the browser only. Load it with a script tag in plain HTML, in a
client-side script in Astro, never in the frontmatter. In React, call
Receipt.mount(ref.current) in useEffect and
destroy() in its cleanup.
-
Tune it, either way
Per element with an attribute, or once for the whole site by editingDEFAULTSat the top of the file.Attribute Default What it is Lower Higher data-receipt-paper #f4ece0 Colour of the paper. Options: any CSS colour. Left on its default, the paper keeps the background of its own class, so a Webflow class or a rule of the page decides. The edge the slot keeps after a tear takes the same colour. data-receipt-ink #15100c Colour of the print: the text, the leaders, the bars of a code. Options: any CSS colour. Left on its default with paper, the text keeps the colour of its own class. Setting either one applies both. data-receipt-trigger view What starts the print. Options: view prints when a third of the block is in the window; scroll feeds the paper as the block rises through the window, and never takes it back when the page scrolls up; manual waits for print(). data-receipt-once on Whether the ticket prints only the first time it is seen: on or off. Options: on prints once and leaves the ticket hanging; off takes the ticket back when the block has left the window, and prints it again the next time. data-receipt-speed 16em Paper the printer feeds in a second, any CSS length. A slow, deliberate printer: every notch can be counted A fast one: under a second for a short ticket, and the notches blur into a slide data-receipt-step 0.5em Length of one notch of the feed, any CSS length. The paper moves a notch, holds, moves the next. Finer notches, a smoother, quieter feed Coarser jolts, and a harder kick to the swing at each one. A third of a line to a whole line reads as a printer data-receipt-pause 0.09 Rest of the print head after each line, in seconds. A separator keeps it four times as long, a total twice, after a rest of three before its run. At 0 the lines follow each other with no beat A slower, more readable print: the whole ticket takes one rest per line longer data-receipt-sway 1 Swing and flap the hanging paper takes from each notch, 0 to 3. At 0 the paper feeds straight, rigid A livelier sheet. The swing never passes 1.6 degrees, so the cut stays behind the lip of the slot data-receipt-curl 1 Forward curl of the hanging paper, 0 to 3: the foot leans towards the eye. At 0 the printed ticket lies flat, and its text is drawn without any transform A foot that leans out more, and looks wider than the head data-receipt-wear 0.5 Thermal flaws, 0 to 1: two pale columns where a dot of the head is tired, and bands where the ink took less. At 0 a clean print Paler streaks and bands. They only lighten the ink, never mark the paper data-receipt-seed 7 Which flaws, and which way the paper swings: any number. Options: the same seed always gives the same ticket; give two tickets of a page two seeds. data-receipt-tear on Whether the printed ticket can be torn off: on or off. Options: on adds a grip over the foot of the ticket, for a pointer, a finger and the keyboard; off leaves the ticket hanging, and its foot selectable. data-receipt-pull 3.4em Travel the paper resists before it rips, any CSS length. A ticket that comes away at the first tug A longer, tenser pull before the first tooth gives data-receipt-again on Whether a new ticket prints after a tear: on or off. Options: on prints the next one half a second after the torn one is gone; off leaves the slot with its edge of paper until print() is called. data-receipt-slot on The slot the paper comes out of: on or off. Options: on draws a dark bezel, a slit and a lip over the top of the block, a little wider than the paper; off draws nothing, and the paper comes out of the top edge of the block, under whatever the page puts there. -
Drive it from JavaScript
When the ticket prints on a click, when a basket adds lines to it, or when the page reacts to it being printed or torn.const element = document.querySelector('[data-receipt]'); element.addEventListener('receipt:printed', (e) => { console.log(e.detail); }); const receipt = Receipt.mount(element); // the block auto() mounted, or a new one receipt.print(); // feed it now; on a hanging ticket, cut it and print the next // A live basket: one more line, and the paper feeds by its height. const row = document.createElement('div'); row.setAttribute('data-receipt-row', ''); row.innerHTML = '<div>Gift wrap</div><div data-receipt-amount>$3.00</div>'; receipt.add(row); // before the total // When the block leaves the page: receipt.destroy(); // removes the slot and the grip, gives back the markup as it was
-
Fit it to your page
- Structure: a block marked
data-receipt, holding one block markeddata-receipt-ticket, the paper. Every child of the paper is one line, in the order it reads. Without the mark the engine takes the first child of the block as the paper. - Making it yours: write your own lines in the paper, as many as you need, and style the paper with your own class: its width, its padding, its type. The paper is as long as its lines, the feed follows that length, and a long label wraps.
- A row: a line marked
data-receipt-rowholds two elements, the label, then the amount markeddata-receipt-amount. The stylesheet lays them at the two ends and draws the dotted leader between them. A line with no mark is plain text: a header, a note. - A separator: a line marked
data-receipt-rule. Its look is the page's, a dashed border in the preview; the mark tells the printer to rest longer on it. - The total: the line marked
data-receipt-total. It is fed in one fast run, and its text is read out by a screen reader once the ticket is printed. - A code: an empty box marked
data-receipt-code="DM-4471-1009". The engine draws the bars of that string as its background, a real Code 128 in the colour of the ink, and names the box for assistive technology. Give the box a height. Characters outside plain ASCII are left out. - One setting for every ticket of the page, without opening the file: declare
window.ReceiptSettings = { speed: '24em' }in a script placed beforereceipt.js. The three levels, least specific first, areDEFAULTS, then that object, then adata-receipt-*attribute on the block itself (data-receipt-tear="off"). - Tearing it: the foot of a printed ticket is a grip. Pressed and pulled down, the paper gives a little, then rips from the corner opposite the pull; let go, it falls. On the keyboard the grip takes the focus, and Enter or Space tears the ticket. Its name for a screen reader is "Tear off the receipt", or the value of
data-receipt-tear-labelon the block. - A live basket:
receipt.add(line)puts a line in a hanging ticket and feeds the paper by its height. With no second argument the line goes before the total, and before the separator above it when there is one;receipt.add(line, before)puts it before a line of your choice. To change an amount or the total, write the new text in the element: the print is the page's own text. - What the script writes:
data-receipt-stateon the block,idlewhile only the edge of the paper is out,printing,printed,tearing,falling, orstaticunder reduced motion. Five nodes markeddata-receipt-part, the slot and the lip inside it, the edge kept after a tear, a status line that is never seen, and the grip. One custom property on the paper,--receipt-hide, and a transform while it moves. - From JavaScript:
Receipt.mount(element, overrides)returns the instance, withelement,settings,state(),progress()from 0 to 1,print(),add(line, before),tear(),show(),reset(),replay(),refresh()anddestroy(). The block emitsreceipt:changewith{ element, state },receipt:print,receipt:linewith{ element, line, index }each time a line has cleared the slot,receipt:printed,receipt:tearwhen the paper comes free andreceipt:tornwhen it is gone. All of them bubble.
- Structure: a block marked
-
Avoid the pitfalls
- Leave the foot of the paper blank. The teeth are cut into the last third of an em, and the edge left at the slot is 0.85em of the same paper: give the paper a bottom padding of 1.5em or more, as the preview does, or the last line is cut by the teeth and shows at the slot before anything is printed.
- The foot of the ticket leaves the slot first. That is how paper comes out of a printer that hangs its ticket: the header is the last thing printed. A page that needs the total to arrive last should not hide it; the eye reads the ticket once it hangs.
- A torn ticket falls outside its block. It is cut by the first ancestor that clips: give the section
overflow: clipwhen the ticket sits near the end of the page, or the fall lengthens the page for a moment. The preview's section does. - The slot is wider than the paper, by 1.5em on each side, and is laid over the top of the block. Leave that room beside the block, or set
slottooffand bring your own. - The block takes a top padding of 0.68em from the stylesheet, the room of the slot above the paper. Do not set a top padding on it; pad a parent.
- Text under the grip is not selectable while
tearis on: the grip covers the foot of the ticket, 4.4em at most. Everything above it selects as usual. - **A ticket taller than three windows never prints on
view**, since a third of it is never in the window at once: usescrollormanual. - After a tear the lines are still in the page. The ticket is drawn back inside the printer, and a screen reader still reads it. To empty it, remove its lines yourself on
receipt:torn. - Changing lines from a script: text can change at any time. Lines added with anything but
add(), or removed, are picked up by the engine, which watches the size of the paper; the paper then takes its new length at once, with no feed.
One click on Copy the AI prompt copies everything an assistant needs to build this effect: the complete code, the markup, the dependency, every setting and every pitfall.
What it does
Receipt is a scroll animation for Webflow and vanilla JavaScript, with no library. Also called receipt printing animation, receipt printer effect or thermal receipt animation.
The order recap that comes out of a printer. The content is an ordinary list in plain markup, a header, rows with a label and an amount, separators, a total, a footer line, a code, and the component turns it into a printed ticket: narrow paper, amounts on the right behind dotted leaders, a foot cut in teeth. The paper feeds out of a slot in notches, like a thermal printer, the foot of the ticket first and each line clearing the slot in its turn; the rhythm of the print head can be read, a short rest after a line, a longer one on a separator, one fast run for the total. Every notch gives the hanging paper a small swing and a flap forward, slower as the ticket gets longer. Once printed the ticket can be torn off: taken by its foot and pulled down, it gives a little, holds, then rips across the slot from one corner to the other, turning about the corner that still holds, comes away in the hand and falls like a sheet when it is let go. The slot keeps the other half of the teeth, a fresh edge of paper, and prints the next one. It prints when it comes into view, with the scroll, or from a script, and a line added to a ticket that hangs makes the paper feed a little more, which is what a live basket or a price calculator needs. A string becomes a real Code 128 barcode. Faint thermal flaws, a pale column, uneven ink, come from a seed. The lines stay the page's own elements: selectable, read in order by a screen reader, the total announced once it is printed. Under reduced motion the ticket hangs printed and nothing moves; without JavaScript it is a plain receipt. No library. Pattern type order summary, price recap, printed ticket.
Updated
Questions
Mark a block data-receipt and the paper inside it data-receipt-ticket: every child of the paper is one line. A line marked data-receipt-row holds a label then an amount marked data-receipt-amount, laid at the two ends with a dotted leader between them; data-receipt-rule is a separator and data-receipt-total the total. The ticket prints when it comes into view.
No. The lines stay the page's own elements, selectable and read in order by a screen reader, and the paper is fed out of the slot behind a clip-path. The teeth of the foot are a CSS mask, and the swing of the hanging paper is computed by the engine.
Yes, with data-receipt-trigger: view, the default, prints when the ticket comes into view, scroll prints with the scroll and manual waits for print() from a script. data-receipt-speed, 16em a second by default, is the paper the printer feeds and data-receipt-pause the rest of the print head after each line.
Yes. The foot of a printed ticket is a grip: pulled down, the paper gives a little, then rips across the slot and falls when it is let go; on the keyboard, Enter or Space tears it. The slot then prints the next one, unless data-receipt-again="off", and data-receipt-tear="off" makes a ticket that only hangs.
Yes. receipt.add(line) puts a line in a hanging ticket, before the total, and feeds the paper by its height; to change an amount, write the new text in the element. An empty box marked data-receipt-code="DM-4471-1009" is drawn as a real Code 128 barcode of that string, in the colour of the ink.