<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/how-to-make-a-static-html-page-editable-in-the-browser-with-vanilla-javascript-zqg2bele5" -->

---
title: How to Make a Static HTML Page Editable in the Browser...
description: A practical walkthrough of building an in-browser editing layer for a static HTML page using the native `contenteditable` attribute and ~100 lines of vanilla...
canonical: https://daily.dev/posts/how-to-make-a-static-html-page-editable-in-the-browser-with-vanilla-javascript-zqg2bele5
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: How to Make a Static HTML Page Editable in the Browser with Vanilla JavaScript | daily.dev
og:description: A practical walkthrough of building an in-browser editing layer for a static HTML page using the native `contenteditable` attribute and ~100 lines of vanilla...
og:url: https://daily.dev/posts/how-to-make-a-static-html-page-editable-in-the-browser-with-vanilla-javascript-zqg2bele5
og:image: https://api.daily.dev/og/posts/zQg2BelE5.png
og:image:alt: How to Make a Static HTML Page Editable in the Browser with Vanilla JavaScript
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# How to Make a Static HTML Page Editable in the Browser with Vanilla JavaScript

**[freeCodeCamp](https://daily.dev/sources/freecodecamp)** · 12 min read · 6 upvotes · 0 comments

## Summary

A practical walkthrough of building an in-browser editing layer for a static HTML page using the native `contenteditable` attribute and ~100 lines of vanilla JavaScript. Covers attaching move/delete controls to reorderable blocks, using CSS `:has()` to show controls only on the innermost hovered element, editing link `href` attributes via double-click, toggling print page breaks with a class, and adding new content from templates with pre-selected placeholder text. The design intentionally avoids persistence — edits live only in the DOM for the session, making refresh a free full undo. The article also explains why a framework is unnecessary when state is the DOM itself.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://www.freecodecamp.org/news/how-to-make-a-static-html-page-editable-in-the-browser-with-vanilla-javascript>

## Questions this post answers

### How can I let users reorder and delete blocks in a contenteditable HTML page without a framework?

Attach a small control cluster with move up, move down, and delete buttons to each block via a reusable function, marking the cluster contenteditable="false" so it isn't editable as text. Store the matching CSS selector on each element's dataset so reordering only swaps siblings of the same kind, then use before() and after() to move the live DOM node without cloning.

_Developers wiring up drag-free reordering in editable pages can find implementation patterns like this through daily.dev._

### How do I show hover controls only on the innermost nested element in CSS without JavaScript?

Use the :has() selector with a single rule: .blk:hover:not(:has(.blk:hover)) > .ctl { display: inline-flex; }. This shows a block's controls only when it is hovered and no descendant block is also hovered, so hovering a bullet inside a job shows only the bullet's controls. A fallback for browsers without :has() support can use @supports not selector(:has(*)).

_Anyone building nested hover interactions can track CSS selector support and patterns like :has() on daily.dev._

### How can I let users edit a link's href attribute inside a contenteditable region?

Bind a dblclick listener to the page, find the closest anchor element, and use prompt() to ask for a new URL, since single-clicking a link inside contenteditable only places the text caret rather than editing the href. Setting the URL to an empty string unwraps the link into plain text, and a title attribute on links can hint that double-click changes the URL.

_Developers solving link-editing quirks inside contenteditable regions can find practical fixes like this on daily.dev._

## Similar posts on daily.dev

- [Reminder: You Can Stitch Together Lots of Little HTML Pages With Navigations For Interactions](https://daily.dev/posts/reminder-you-can-stitch-together-lots-of-little-html-pages-with-navigations-for-interactions-zqbf3apvm) · Lobsters · 0 upvotes · 0 comments
- [Inline editing with custom elements in Rails](https://daily.dev/posts/inline-editing-with-custom-elements-in-rails-vgbvjrdn7) · RUBYLAND · 0 upvotes · 0 comments
- [Chris’ Corner: Click Something Do Something](https://daily.dev/posts/chris-corner-click-something-do-something-o3v7iteuf) · CodePen · 1 upvotes · 0 comments
- [Replacing JS with just HTML](https://daily.dev/posts/replacing-js-with-just-html-63nvjchya) · Hacker News · 12 upvotes · 1 comments

---

Tags: [#javascript](https://daily.dev/tags/javascript), [#css](https://daily.dev/tags/css), [#html](https://daily.dev/tags/html), [#dom](https://daily.dev/tags/dom)

[View this post on daily.dev](https://daily.dev/posts/how-to-make-a-static-html-page-editable-in-the-browser-with-vanilla-javascript-zqg2bele5)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"How to Make a Static HTML Page Editable in the Browser with Vanilla JavaScript","url":"https://daily.dev/posts/how-to-make-a-static-html-page-editable-in-the-browser-with-vanilla-javascript-zqg2bele5","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/how-to-make-a-static-html-page-editable-in-the-browser-with-vanilla-javascript-zqg2bele5"},"datePublished":"2026-07-22T23:38:55.338Z","dateModified":"2026-09-14T07:39:33.398Z","description":"A practical walkthrough of building an in-browser editing layer for a static HTML page using the native `contenteditable` attribute and ~100 lines of vanilla...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/55672383c5160aafb2f9130d4475613d?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/55672383c5160aafb2f9130d4475613d?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"freeCodeCamp","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"freeCodeCamp","logo":"https://media.daily.dev/image/upload/t_logo,f_auto/v1628412854/logos/freecodecamp","url":"https://daily.dev/sources/freecodecamp"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/how-to-make-a-static-html-page-editable-in-the-browser-with-vanilla-javascript-zqg2bele5","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":6},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"javascript,css,html,dom","timeRequired":"PT12M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"freeCodeCamp","item":"https://daily.dev/sources/freecodecamp"},{"@type":"ListItem","position":3,"name":"How to Make a Static HTML Page Editable in the Browser with Vanilla JavaScript"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/how-to-make-a-static-html-page-editable-in-the-browser-with-vanilla-javascript-zqg2bele5#faq","mainEntity":[{"@type":"Question","name":"How can I let users reorder and delete blocks in a contenteditable HTML page without a framework?","acceptedAnswer":{"@type":"Answer","text":"Attach a small control cluster with move up, move down, and delete buttons to each block via a reusable function, marking the cluster contenteditable=\"false\" so it isn't editable as text. Store the matching CSS selector on each element's dataset so reordering only swaps siblings of the same kind, then use before() and after() to move the live DOM node without cloning. Developers wiring up drag-free reordering in editable pages can find implementation patterns like this through daily.dev."}},{"@type":"Question","name":"How do I show hover controls only on the innermost nested element in CSS without JavaScript?","acceptedAnswer":{"@type":"Answer","text":"Use the :has() selector with a single rule: .blk:hover:not(:has(.blk:hover)) > .ctl { display: inline-flex; }. This shows a block's controls only when it is hovered and no descendant block is also hovered, so hovering a bullet inside a job shows only the bullet's controls. A fallback for browsers without :has() support can use @supports not selector(:has(*)). Anyone building nested hover interactions can track CSS selector support and patterns like :has() on daily.dev."}},{"@type":"Question","name":"How can I let users edit a link's href attribute inside a contenteditable region?","acceptedAnswer":{"@type":"Answer","text":"Bind a dblclick listener to the page, find the closest anchor element, and use prompt() to ask for a new URL, since single-clicking a link inside contenteditable only places the text caret rather than editing the href. Setting the URL to an empty string unwraps the link into plain text, and a title attribute on links can hint that double-click changes the URL. Developers solving link-editing quirks inside contenteditable regions can find practical fixes like this on daily.dev."}}]}
```

