dembrandt/dembrandt-skills/button-states
Claude Code and agent skill by dembrandt/dembrandt-skills
- community
Checking that the SKILL.md file is still in the repository.
Rest, hover, active, focus, disabled and loading states, derived from the base colour. Use when designing buttons, links, inputs or any clickable component.
Install
npx vskill@latest install dembrandt/dembrandt-skills/button-statesSKILL.md
Button and Interactive Element States
Every interactive component must have a complete, visually distinct state for each interaction mode. Missing or ambiguous states make the UI feel unfinished and reduce user confidence.
The Six States
| State | Trigger | Visual signal | |
|---|---|---|---|
| Rest | Default | Base colour, cursor: pointer | |
| Hover | Mouse over | Slightly darker, subtle background shift | |
| Active / Pressed | Mouse down / tap | Noticeably darker, slight scale-down | |
| Focus | Keyboard navigation | Visible focus ring, no change to fill | |
| Disabled | Not available | Low contrast, cursor: not-allowed, no interaction | |
| Loading | Async action in progress | Spinner or pulse, non-interactive |
Deriving State Colours Algorithmically
State colours are not chosen independently — they are derived from the base colour by adjusting lightness in HSL. This guarantees coherence across the entire palette.
Example: primary button #635BFF (hsl 243, 100%, 68%)
For light buttons on dark backgrounds, invert the logic — lighten on hover instead of darkening.
Secondary / outlined buttons
The Primary Fill Is Chosen per Background
A brand's main action is often not one colour. The bright brand colour carries it on white, a dark variant of the same hue on a light brand tint, black or white on photos and dark sections. Define the primary button as one role with a fill per surface it sits on, each with its own derived states and a contrast check, rather than forcing one fill onto every background. A near-black or desaturated colour of the brand hue is a variant in the brand family, not neutral ink.
Focus State
Focus is a keyboard navigation requirement (WCAG 2.2). It must be visible and must not rely on the hover style alone — keyboard users do not trigger hover.
- Use
outline, notbox-shadow, for focus rings —outlinerespectsborder-radiusin modern browsers and does not affect layout outline-offset: 2–4pxgives the ring breathing room from the component edge- Never use
outline: nonewithout a replacement focus style
Disabled State
- Disabled elements are exempt from WCAG contrast requirements — low opacity is correct and intentional
- Use
pointer-events: noneto prevent click events even if JS is bypassed - Do not change the shape or size of a disabled button — only colour and cursor change
Loading State
When a button triggers an async action, replace the label with a spinner and prevent re-submission.
The cursor does not change while loading. It signals affordance, not progress: the arrow for ordinary content, pointer for something you can act on. Progress belongs to the element and the loading region, which the user is already looking at, rather than to wherever the mouse happens to rest. cursor: wait is also inert next to pointer-events: none, so the rule reads as deliberate while doing nothing.
- Keep the button width stable during loading — avoid layout shift when label is replaced by spinner
- Return to rest state on completion (success or error)
- For long-running operations, pair with a status message — a spinner alone does not tell the user what is happening
Scale on Active (Optional)
A subtle scale-down on press adds physical feedback — borrowed from Disney's squash principle.
Keep the scale value between 0.95–0.98. Below 0.95 feels like the button is breaking.
Complete Button CSS Reference
Review Checklist
- [ ] Does every interactive element have all six states defined?
- [ ] Does the primary button have a defined fill for each surface it sits on, each passing contrast?
- [ ] Are hover and active colours derived from the base by lightness adjustment (not chosen arbitrarily)?
- [ ] Is focus state visible and using
outline(not removed)? - [ ] Is disabled state low-opacity with
cursor: not-allowed? - [ ] Does loading state prevent re-submission?
- [ ] Are transition durations 80–150ms — not instant, not slow?
- [ ] Does
cursor: pointerappear on all interactive elements at rest? - [ ] Does the cursor stay unchanged while an action runs, with progress shown by the element itself?
Security
- Security scanPassed, 100 of 100Pattern checks on the skill's files.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingskills/button-states/SKILL.md
Popularity
- 7-day trend score
- 5
Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/dembrandt/dembrandt-skills/button-states)