Pixel UI Kit
A pixel-art UI trio — a stepped-border card, a pixel button that sinks on press, and a block-by-block progress bar, all drawn with box-shadow and CSS.
One component, three sub-components: PixelUiKit is the container that owns the size and accent colour (written to --wb-pixel-accent), with PixelUiKit.Card, PixelUiKit.Button and PixelUiKit.Progress attached as static properties. No pixel border uses an image — stacked box-shadow layers push one cell out on each side and leave the corners empty, giving a stepped, notched corner. Cards jump one cell on hover, buttons hard-cut down when pressed, and the progress bar lights up cell by cell. Typography is left to your site; the component only uses font-mono.
Bring this into your project
Run this command in your project folder. The CLI adds the source and dependencies; then follow the usage example below.
npx webberui@latest add pixel-ui-kit.enPlayground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
<PixelUiKit/>
The complete example includes the preview layout and data. Install the component first, then paste this file into your project.
Installation
npx webberui@latest add https://webberui.com/r/pixel-ui-kit.en.jsonOr, once registries are configured in components.json, install it as @webberui/pixel-ui-kit.
Usage
import { PixelUiKit } from "@/components/ui/pixel-ui-kit";
const [days, setDays] = React.useState(3);
<PixelUiKit size="md" accent="#22c55e">
<PixelUiKit.Card title="Level 1">
<p>Daily check-in {days}/5</p>
<PixelUiKit.Progress value={(days / 5) * 100} label="Check-in progress" striped />
<PixelUiKit.Button variant="secondary" onClick={() => setDays((d) => Math.min(5, d + 1))}>
+1
</PixelUiKit.Button>
<PixelUiKit.Button variant="primary" disabled={days < 5}>
Claim reward
</PixelUiKit.Button>
</PixelUiKit.Card>
</PixelUiKit>Props
PixelUiKit
| Prop | Type | Default | Description |
|---|---|---|---|
size | "sm" | "md" | "md" | Kit size: affects font size, padding and progress bar height |
accent | string | "#22c55e" | Accent colour, written to --wb-pixel-accent; used by primary buttons and the progress fill |
children | ReactNode | — | Children (Card / Button / Progress or any content) |
className | string | — | Passed through to the outermost container |
PixelUiKit.Card
| Field | Type | Default | Description |
|---|---|---|---|
title | ReactNode | — | Title bar text; the title bar is hidden when omitted |
icon | ReactNode | — | Optional icon at the left of the title bar, gets image-rendering: pixelated |
children | ReactNode | — | Card content |
className | string | — | Passed through to the card root |
PixelUiKit.Button
| Field | Type | Default | Description |
|---|---|---|---|
variant | "primary" | "secondary" | "danger" | "primary" | Appearance: primary (accent), secondary (neutral), danger (red) |
children | ReactNode | — | Button content |
onClick | (event: MouseEvent) => void | — | Click handler |
disabled | boolean | false | Disables the button |
type | "button" | "submit" | "reset" | "button" | Native button type |
className | string | — | Passed through to the button element |
PixelUiKit.Progress
| Field | Type | Default | Description |
|---|---|---|---|
value | number | — | Controlled progress value (0–100); falls back to defaultValue when omitted |
defaultValue | number | 0 | Initial progress value for uncontrolled mode (0–100) |
segments | number | 20 | Number of segments |
striped | boolean | false | Show looping stripes on filled segments |
label | string | "Progress" | Progress bar name, used as aria-label and shown above the bar (the Chinese registry defaults to "進度" (Progress)) |
className | string | — | Passed through to the progress root |
CSS variables
| Field | Type | Default | Description |
|---|---|---|---|
--wb-pixel-size | length | 4px | Edge length of one pixel cell; override on any ancestor |
--wb-pixel-accent | color | #22c55e | Accent colour (written by the accent prop) |
--wb-pixel-step | time | 40ms | Delay between cells lighting up in the progress bar |
--wb-pixel-press | time | 60ms | Duration of the button sink and the card jump |
How it works
- Stepped border: four
box-shadowlayers each push one--wb-pixel-sizecell out from a side, leaving the corners empty — the notched outline familiar from pixel games. Cards add a dark drop shadow offset two cells to the bottom right. - On hover the card moves up one cell with
steps(2)— it jumps instead of sliding — and returns while pressed. - Buttons have a two-cell bottom edge; on press they hard-cut with
steps(1): the whole button sinks two cells and the edge drops to zero, so the top edge stays put and it reads as a key being pushed in. - The progress bar splits 0–100 into
segmentscells; each lights up or dims via a 0s transition plus an increasing delay of--wb-pixel-step. Withstriped, filled cells show stripes looping withsteps(4). - Line, surface and shadow colours are CSS variables set on the container for light and dark, so the sub-components follow the theme.
Accessibility
PixelUiKit.Buttonis a real<button>withtype="button"by default; keyboard focus shows a 2px dashed pixel outline- When a card has a title, it is linked to the card via
aria-labelledby PixelUiKit.Progressisrole="progressbar"witharia-label,aria-valuenow,aria-valuemin,aria-valuemaxandaria-valuetext; a text percentage is shown besides colour- When the system "reduce motion" setting is on, cards do not jump on hover, the progress bar fills straight to its target and the stripes do not animate
Foil Surface
A foil finish that wraps any content: five gradient layers with blend modes shift their sheen with scroll progress and pointer position, without any tilt.
Perspective Carousel
A 3D perspective carousel (coverflow style) with drag to page, looping, autoplay, and controlled and uncontrolled modes.