KQ-1484 · STRIP/SHRED
Strip Shred
A delete control with a shredder under the card: confirming makes the teeth bite on springs.flick, then the motor pulls the card into the mouth at a steady rate with a stick-slip judder while the teeth and the head shiver, and the card comes out underneath as strips that roll toward you as they hang, printed with the fragments of the card's own words that were in each column, before each lets go on a seeded beat and falls into the bin. Undo springs every strip back up on springs.snap in a cascade and feeds the card back out on springs.glide; the button cycles Delete, Confirm, Undo with a draining ring, Deleting and Deleted in one place, so Enter, Space, Escape and the Delete key all work without focus moving.
Fieldline · draft
Launch notes
v2 ships Tuesday. Brief support before the post goes out.
draft kept · press delete
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/strip-shred
Props
- children
- ReactNode
- default —
- The card's content. The component draws the card's paper, border and padding around it.
- label
- string
- default "Delete"
- The button's idle label and accessible name.
- confirmLabel
- string
- default "Confirm"
- The label while it waits for a second press.
- undoLabel
- string
- default "Undo"
- The label from the shred until the undo window closes.
- deletingLabel
- string
- default "Deleting"
- The label while onDelete's promise is pending.
- deletedLabel
- string
- default "Deleted"
- The label once the delete has landed.
- shreddedLabel
- string
- default "Shredded"
- Printed in the dashed outline left where the card was.
- onDelete
- () => void | Promise<unknown>
- default —
- Called when the undo window closes. Return a promise to show the pending state; a rejection reassembles the card.
- onUndo
- () => void
- default —
- Called when the visitor undoes the shred.
- deleted / defaultDeleted
- boolean
- default — / false
- Whether the card has been deleted. A host setting it back to false reassembles the card; setting it true shreds it without a window.
- onDeletedChange
- (deleted: boolean) => void
- default —
- Fires with true when the delete lands.
- onPhaseChange
- (phase: "idle" | "armed" | "shredding" | "undo" | "deleting" | "deleted" | "restoring") => void
- default —
- Fires on every step of the cycle, from the press or timer that caused it.
- strips
- number
- default 10
- How many strips the cutters make, 3 to 24.
- undo
- number
- default 5000
- The undo window after the shred, in ms; 0 deletes as soon as the shred finishes.
- speed
- number
- default 1
- The motor's speed, 0.25 to 3: the feed, the slips and the fall all scale with it.
- curl
- number
- default 0.6
- How far the strips roll toward you as they hang, 0 to 1.
- resistance
- number
- default 0.5
- How hard the paper fights the cutters: the depth of the stick-slip judder, 0 to 1.
- confirm
- boolean
- default true
- Ask for a second press before shredding.
- paper
- string
- default "var(--card)"
- The card's paper, any CSS colour; the strips are cut from it and their turned-over backs are mixed from it in oklab.
- ink
- string
- default "var(--ink-2)"
- The colour of the word fragments printed on the strips.
- size
- "sm" | "md" | "lg"
- default "md"
- Width cap, head, button and bin size.
- sound
- boolean
- default false
- Play the motor's scratch (stepping with each slip), the thud of the last strip and a softer one when an undo lands. Only ever in answer to a press or key.
- disabled
- boolean
- default false
- Disables the button.
- className
- string
- default —
- Classes for the root; it is w-full up to its size's max width.
| Prop | Type | Default | Description |
|---|---|---|---|
| children | ReactNode | — | The card's content. The component draws the card's paper, border and padding around it. |
| label | string | "Delete" | The button's idle label and accessible name. |
| confirmLabel | string | "Confirm" | The label while it waits for a second press. |
| undoLabel | string | "Undo" | The label from the shred until the undo window closes. |
| deletingLabel | string | "Deleting" | The label while onDelete's promise is pending. |
| deletedLabel | string | "Deleted" | The label once the delete has landed. |
| shreddedLabel | string | "Shredded" | Printed in the dashed outline left where the card was. |
| onDelete | () => void | Promise<unknown> | — | Called when the undo window closes. Return a promise to show the pending state; a rejection reassembles the card. |
| onUndo | () => void | — | Called when the visitor undoes the shred. |
| deleted / defaultDeleted | boolean | — / false | Whether the card has been deleted. A host setting it back to false reassembles the card; setting it true shreds it without a window. |
| onDeletedChange | (deleted: boolean) => void | — | Fires with true when the delete lands. |
| onPhaseChange | (phase: "idle" | "armed" | "shredding" | "undo" | "deleting" | "deleted" | "restoring") => void | — | Fires on every step of the cycle, from the press or timer that caused it. |
| strips | number | 10 | How many strips the cutters make, 3 to 24. |
| undo | number | 5000 | The undo window after the shred, in ms; 0 deletes as soon as the shred finishes. |
| speed | number | 1 | The motor's speed, 0.25 to 3: the feed, the slips and the fall all scale with it. |
| curl | number | 0.6 | How far the strips roll toward you as they hang, 0 to 1. |
| resistance | number | 0.5 | How hard the paper fights the cutters: the depth of the stick-slip judder, 0 to 1. |
| confirm | boolean | true | Ask for a second press before shredding. |
| paper | string | "var(--card)" | The card's paper, any CSS colour; the strips are cut from it and their turned-over backs are mixed from it in oklab. |
| ink | string | "var(--ink-2)" | The colour of the word fragments printed on the strips. |
| size | "sm" | "md" | "lg" | "md" | Width cap, head, button and bin size. |
| sound | boolean | false | Play the motor's scratch (stepping with each slip), the thud of the last strip and a softer one when an undo lands. Only ever in answer to a press or key. |
| disabled | boolean | false | Disables the button. |
| className | string | — | Classes for the root; it is w-full up to its size's max width. |