For the complete documentation index, see llms.txt. Markdown variants are available by appending .md to any URL or sending an Accept: text/markdown header. The dithercn agent skill, for building any dither on the engine, is at /.well-known/agent-skills/dithercn/SKILL.md.
dithercn

Dither button

A button with a lit, dithered surface: a highlight dithered down from the top, a shade dithered up from the bottom, brighter on hover and pressed in on click.

Controls
Fill
Colour
Size
Bloom
Cell2px
Loading

Installation

pnpm dlx shadcn@latest add https://dithercn.dev/r/dither-button.json

Usage

import { DitherButton } from "@/components/dithercn/dither-button";
 
export function Actions() {
  return (
    <>
      <DitherButton color="blue">Deploy</DitherButton>
      <DitherButton variant="outline" fill="dotted">
        View logs
      </DitherButton>
    </>
  );
}

DitherButton renders a real <button> with type="button" unless you pass another type. A filled button is lit like a pixel-art bevel: the full colour, with a highlight (the colour mixed towards white) dithered down from the top and a shade (mixed towards black) dithered up from the bottom, so the Bayer steps show at rest. Hover fades in a longer, denser highlight. Press fades in a shade from the top, so the face looks pushed in. Only opacity animates, so the cells stay on the grid.

outline buttons are a faint tint inside a hairline edge, with the plain colour dithered up from the bottom. Hover and press make that dither denser and taller, which suits secondary actions.

The label is dark on the bright dark-theme colours and light on the deeper light-theme ones.

Examples

Fills and colours

Every fill in four colours, filled and outline. fill sets the texture of the shade: gradient is a Bayer ramp up from the bottom, dotted a staggered dot lattice, hatched rising diagonals, and solid a thin dithered rim along the bottom edge. The top highlight is the same on all four.

Loading in a form

loading keeps the label and the button's width, steps three cells before the label, pulses the hover highlight, and sets aria-busy. Clicks are ignored until it clears. Submit this one to see it.

Pass asChild and a single child, such as Next.js Link or a plain <a>, and the child gets the button's look and fill. It stays a link: right click and middle click work, and the router handles navigation.

Props

PropTypeDefault
variant

Filled is the lit colour surface. Outline is a faint tint whose dither grows on hover.

Type: "filled" | "outline"Default "filled"
fill

Texture of the shade: a Bayer ramp, a dot lattice, diagonals, or a thin rim.

Type: "gradient" | "dotted" | "hatched" | "solid"Default "gradient"
color

A palette name such as "blue" or "green", a CSS variable name, or any CSS colour.

Type: DitherColorDefault "ink"
size

Heights of 32, 36 and 44 pixels. icon is a 36 pixel square for a lone icon; give it an aria-label.

Type: "sm" | "md" | "lg" | "icon"Default "md"
bloom

A soft glow in the button's colour that follows the cells.

Type: "off" | "low" | "high"Default "off"
cell

Size of one dither cell in CSS pixels.

Type: numberDefault 2
loading

Busy state: keeps the label, ignores clicks and sets aria-busy.

Type: booleanDefault false
asChild

Render your own single child, such as a link, with the button's look.

Type: booleanDefault false

All other props pass through to the <button>, or to your child with asChild.

Notes

  • Focus shows a 2 pixel outline with :focus-visible and the hover highlight, so keyboard users see the same step as pointer users.
  • Hover only applies on devices that can hover. Press works everywhere, so touch screens get the pressed-in shade as feedback.
  • With reduced motion, the layers switch without fading, the press does not scale, and the loading cells hold still.
  • Disabled and loading buttons drop to 45% opacity and a not-allowed or progress cursor. For a disabled link, set aria-disabled on it and leave out href.
  • The fill is plain CSS masks in one shared <style> tag. The button only needs client JavaScript for asChild and loading.