KQ-1125 · FILTER/SWIPE
Filter Swipe
A photo whose look changes as you swipe across it: the boundary between the current look and the incoming one sits under the finger 1:1 with the incoming look's name riding it, and a release that carries or throws it past the threshold runs on to the far edge on the glide spring with the release velocity, while a short one slides back. The incoming look is the same picture under another CSS filter, revealed by a mask that is crisp or feathered, and past the first or last look the picture rubber-bands. The looks are also a radio group of dots whose arrow keys slide each look in from the side a swipe would, with the same swish and click.
Swipe across the picture for the next or previous look. Arrow keys choose a look, Home and End the first and last.
look · original · 1 of 5 · swipe across
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/filter-swipe
Props
- children
- ReactNode
- default —
- The picture. It is drawn twice, the look underneath and the look coming in, so keep ids out of it.
- alt
- string
- default —
- What the picture shows: its accessible name, followed by the current look ("Coldbrook harbour at dawn, Harvest look").
- filters
- "film" | "mono" | "tone" | { name: string; filter: string }[]
- default "film"
- A built-in set of five looks, or your own list of named CSS filter values. Names must be unique.
- value / defaultValue
- number
- default 0
- The look on the photo, by index. Controlled or uncontrolled; a slide runs on while the value agrees with it and slides back when it does not.
- onValueChange
- (index: number, look: FilterSwipeLook) => void
- default —
- Fires from the release, key or dot that chose a look, with its index and the look.
- threshold
- number
- default 0.5
- How far across the boundary must be carried, or thrown, to commit: 0.2 to 0.8 of the width, judged on the projected throw. Notches on the frame's edges mark it while dragging.
- label
- boolean
- default true
- The incoming look's name rides the boundary in a pill that turns light once a release would commit, and the current look's name sits in the corner at rest.
- edge
- "hard" | "soft"
- default "hard"
- A crisp boundary with a light rule on it, or a feathered blend with no rule.
- sound
- boolean
- default false
- A swish as a released slide sets off (higher and louder when it commits, low and soft when it goes back) and a click on the frame the new look lands. Nothing plays, and no audio context exists, unless this is on.
- disabled
- boolean
- default false
- Dims the photo and ignores swipes, dots and keys.
- className
- string
- default —
- Merged onto the frame's classes; the frame is w-full at 4:3 unless an aspect class here says otherwise.
| Prop | Type | Default | Description |
|---|---|---|---|
| children | ReactNode | — | The picture. It is drawn twice, the look underneath and the look coming in, so keep ids out of it. |
| alt | string | — | What the picture shows: its accessible name, followed by the current look ("Coldbrook harbour at dawn, Harvest look"). |
| filters | "film" | "mono" | "tone" | { name: string; filter: string }[] | "film" | A built-in set of five looks, or your own list of named CSS filter values. Names must be unique. |
| value / defaultValue | number | 0 | The look on the photo, by index. Controlled or uncontrolled; a slide runs on while the value agrees with it and slides back when it does not. |
| onValueChange | (index: number, look: FilterSwipeLook) => void | — | Fires from the release, key or dot that chose a look, with its index and the look. |
| threshold | number | 0.5 | How far across the boundary must be carried, or thrown, to commit: 0.2 to 0.8 of the width, judged on the projected throw. Notches on the frame's edges mark it while dragging. |
| label | boolean | true | The incoming look's name rides the boundary in a pill that turns light once a release would commit, and the current look's name sits in the corner at rest. |
| edge | "hard" | "soft" | "hard" | A crisp boundary with a light rule on it, or a feathered blend with no rule. |
| sound | boolean | false | A swish as a released slide sets off (higher and louder when it commits, low and soft when it goes back) and a click on the frame the new look lands. Nothing plays, and no audio context exists, unless this is on. |
| disabled | boolean | false | Dims the photo and ignores swipes, dots and keys. |
| className | string | — | Merged onto the frame's classes; the frame is w-full at 4:3 unless an aspect class here says otherwise. |