matthewp/views-the-hard-way/hardview
Claude Code and agent skill by matthewp/views-the-hard-way
- community
Checking that the SKILL.md file is still in the repository.
Create vanilla JavaScript view components using the "Views the Hard Way" pattern. Use when asked to create a view, component, or UI element with raw/vanilla JavaScript DOM manipulation, or when the user mentions "hardview" or "views the hard way".
Install
npx vskill@latest install matthewp/views-the-hard-way/hardviewSKILL.md
Views the Hard Way
A pattern—not a library—for building views using plain JavaScript with native browser APIs. This approach emphasizes directness over abstraction, achieving maximum performance with zero dependencies.
Why This Pattern?
- Performance: Direct imperative code eliminates unnecessary operations
- Zero dependencies: Code never requires upgrades or breaking changes
- Portability: Views work across frameworks and communities
- Maintainability: Strict conventions ensure consistency
- Debugging: Shallow stack traces make troubleshooting straightforward
- Functional approach: Plain functions without classes or side effects
Structure of Every View
Each view module has exactly three parts:
1. The Template
HTML structure defined in a <template> element. Use static markup only—no interpolations. Mark elements with identifiers (IDs, classes, or data attributes) for later querying.
2. The Clone Function
A helper that efficiently duplicates the template:
Use .firstElementChild when you need an element rather than a fragment:
3. The Init Function
Creates a closure containing all view state and logic. Returns an update() function that parent views call to pass props and receive the rendered DOM.
The Six Sections Inside init()
The init() function is organized into clearly-marked sections in this exact order:
Section 1: DOM Variables
Cached references to DOM elements that need updating. Named with Node suffix.
Section 2: DOM Views
References to child view instances. Named with update prefix. These are other views composed within this view.
Section 3: State Variables
Non-DOM data like strings, numbers, or objects. These enable conditional updates to prevent unnecessary DOM mutations.
Section 4: DOM Update Functions
The ONLY place where DOM mutations occur. Named as set[Node]Node() matching the DOM variable name.
These functions:
- Take a value and apply it directly to the DOM
- Do NOT check if the value changed (that's the state setter's job)
- Are simple and focused—one DOM mutation per function
Section 5: State Update Functions
Modify state variables and trigger corresponding DOM updates. Named as set[Name]() matching the state variable.
These functions:
- Always check if the value actually changed before proceeding
- Update the state variable
- Call the corresponding DOM update function
- Prevent redundant DOM operations
Section 6: State Logic
Helper functions for derived state or computations.
Section 7: Event Dispatchers
Functions that emit custom events to parent components.
Section 8: Event Listeners
Named functions that handle DOM events. Never use anonymous functions for event listeners—named functions can be removed later and are easier to debug.
Section 9: Init Functionality
Setup code that runs once. This section:
- Sets initial state values
- Defines
connect()to attach event listeners - Calls
connect()immediately - Defines
disconnect()to remove event listeners (for components that may be removed from the DOM)
Note: The connect/disconnect pattern is only necessary for components that may be dynamically added or removed from the DOM. For static components, you can simply attach listeners directly in this section without the connect/disconnect functions.
The Update Function
Always the last thing in init(). Receives props from parent, calls state setters, returns the DOM. If using connect/disconnect, attach them as properties on update.
Critical Rules
Exclusive Mutation
- DOM must only be modified through DOM Update Functions (
set[Node]Node) - State must only be modified through State Update Functions (
set[Name]) - This consolidates logic and enables reliable debugging via breakpoints
Props Down, Events Up
- Data flows downward through
update(data)function arguments - Child events bubble up through CustomEvent or callbacks
- Never reach up into parent state
Single Responsibility
- Each state variable maps to one corresponding DOM update function
- If a state variable affects multiple DOM nodes, either:
- Create one DOM update function that handles all related nodes
- Split into multiple state variables
Conditional Updates
Always check if values changed in state setters:
Complete Example
Example with Child Views
Example with Events (Counter)
TypeScript
When using TypeScript, add types minimally and let inference handle most things. Only add explicit types where TypeScript can't infer correctly.
What to type explicitly
Props interface - Define an interface for the data parameter:
DOM query results - querySelector returns Element | null, so cast to the specific element type:
Clone return - firstElementChild can be null, so assert:
What to let TypeScript infer
- Return type of
init()- inferred from the function body - Return type of
update()- inferred as the element type - State variable types (usually) - inferred from initial assignment
- Internal function signatures - inferred from usage
Export the view type
This is the start of the file. Read the full SKILL.md on GitHub.
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/hardview/SKILL.md
Popularity
- Repository stars
- 420
- Repository forks
- 12
- 7-day trend score
- 30
Stars and forks are for the whole GitHub repository, not this skill alone. Refreshed 19 Mar 2026, 7 months ago.
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/matthewp/views-the-hard-way/hardview)