[HN Gopher] Mastering DOM manipulation with vanilla JavaScript
       ___________________________________________________________________
        
       Mastering DOM manipulation with vanilla JavaScript
        
       Author : srirangr
       Score  : 346 points
       Date   : 2023-11-06 13:41 UTC (7 hours ago)
        
 (HTM) web link (phuoc.ng)
 (TXT) w3m dump (phuoc.ng)
        
       | snide wrote:
       | Excellent list and examples. Browsing through a dozen or so of
       | these I'm amazed at the care and detail in the examples. They are
       | not only functional, but provide very solid UI work as well.
       | 
       | As I've shifted away from platforms like React to smaller,
       | minimalist implementations, I often have trouble finding ways for
       | how to do complex patterns in standard JS. It's funny when you
       | look at the code and think... huh, that's actually a lot easier
       | than importing a huge library with way too many props :)
       | 
       | Thanks to the author for putting this together.
        
         | bob1029 wrote:
         | > It's funny when you look at the code and think... huh, that's
         | actually a lot easier than importing a huge library with way
         | too many props
         | 
         | I had this realization after the 3rd or 4th RiotJS major
         | version update. It started getting harder to do it the
         | opinionated way. I realized that _every_ minimalistic JS
         | framework would eventually suffer this fate as totally innocent
         | feature requests gradually accumulate into a monstrous pile of
         | hooks, events and other side-effect bandaids.
         | 
         | I don't even use jQuery anymore. I will use things like ES
         | modules to help organize code, but you _don 't_ need to run a
         | goddamn npm command to use any of that technology. All of this
         | is a _global browser standard_ , not something you have to
         | vendor in.
         | 
         | I look at MDN as the Bible these days. If you take a leap of
         | faith, it _will_ carry you almost 100% of the way. The
         | frameworks will cripple you after a certain point. I can 't say
         | this would have been true ~5 years ago. Things have shifted
         | rapidly with browser APIs converging on a powerful set of
         | primitives (modules, flexbox, grid, etc) that are now very
         | consistent across platforms.
        
           | reactordev wrote:
           | I like the fact that you said "I can't say this would have
           | been true ~5 years ago".
           | 
           | React et al. exist because there weren't global standards
           | around these things and composability suffered. Now that we
           | are all playing the same chorus, these frameworks provide
           | little more than component libraries to reuse. This can be
           | done with ES modules. JSX is why most React folks stick with
           | React, not knowing they can use Preact or just NakedJSX if
           | they wish.
           | 
           | I just wanted to verbally concur that vanilla JS is more than
           | capable of doing everything you need. Custom tags. Shadow
           | dom. Composed UI. etc. if you are ok with returning
           | HTMLElement vs a JSX closure.
        
             | snide wrote:
             | And this is absolutely true in CSS now as well. I find a
             | lot of people are needing to rediscover the standards now
             | that they've upped their featuresets.
        
             | irrational wrote:
             | I though React, et al were originally created as a better
             | way to manage DOM updates (shadow DOM). Has that need gone
             | away?
        
               | evan_ wrote:
               | React et al use a virtual DOM, not shadow DOM (unless you
               | specifically render it to shadow DOM).
               | 
               | They are a better* way to manipulate DOM in that you no
               | longer _need_ to manipulate the DOM, you just build a
               | function that returns what the DOM should look like and
               | it figures out what transforms need to happen.
               | 
               | *They're pitched as a better way, and I think it's
               | better, but people can reasonably disagree
        
               | nicoburns wrote:
               | Not at all. Without React (or a similar framework) you
               | are still left with the options of:
               | 
               | - Manually keep track of UI state (which is complex, and
               | often leads to hard to maintain spaghetti code)
               | 
               | - Recreate an entire DOM tree every time you re-render
               | (which is slow to the extent that it will often lead to
               | performance problems in practice). Apparently this is not
               | as slow as it used to (so you could probably get away
               | with this sometimes - and you could before), but it's
               | still generally a better idea to use a framework as you
               | get better performance for very low cost.
               | 
               | There are plenty of non-React frameworks that will you
               | these benefits too. And many of them are much smaller. I
               | think the reason to use React specifically is more
               | "business reasons" such assurances that the framework
               | will continue to be maintained, library ecosystem,
               | developer pool, etc. Other frameworks are often
               | technically superior, the difference just isn't that
               | great.
        
             | nine_k wrote:
             | One of the points of React vs e.g. jQuery was the ability
             | to do efficient updates in large DOM.trees.
             | 
             | Did something arrive to plain JS APIs to allow this in a
             | simple enough way?
        
               | r-spaghetti wrote:
               | It depends on the type of relations between the updates
               | you want to make, for example adding/removing a class can
               | group DOM elements. Updating all elements with this class
               | is easy.
        
               | kevindamm wrote:
               | Templates and shadow DOM help a lot with creating and
               | cloning of large subtrees, but time to first render and
               | caution around page re-layout still require attention to
               | do well at scale.
        
               | wruza wrote:
               | _the ability to do efficient updates in large DOM.trees_
               | 
               | It was the ability to do efficient updates based on large
               | VDOM diffs. The speed of updates is the same between a
               | React VDOM-diff update plan and a direct update of the
               | same size based on e.g. observers.
        
               | nine_k wrote:
               | Yes, that's the point: computing what needs to change
               | using observers quickly becomes hard. React allows you to
               | run all updates against an unchanged view; observers can
               | interact with each other's updates.
               | 
               | While React proper may be too large, I find the approach
               | indispensable for more complex interfaces. One can pick
               | Preact instead.
               | 
               | But it's indeed overkill for adding small bits of
               | interactivity to large, mostly static documents.
        
             | nicoburns wrote:
             | > JSX is why most React folks stick with React, not knowing
             | they can use Preact or just NakedJSX if they wish.
             | 
             | The large ecosystem of component libraries and the backing
             | of a large corporate company is why people continue to use
             | React. That, and that the extra 100kb that comes with React
             | is generally dwarfed by the actual application in any large
             | app.
        
               | explaininjs wrote:
               | I'm using preact for a few projects and the integration
               | with React stuff is _generally_ seamless, but there are
               | enough rough edges encountered that looking back I wouldn
               | 't mind taking the difference of a few dozen kB to avoid
               | them all. The _vast_ majority of my load time is taken by
               | TTFB, even from the Cloudflare Pages local cache, so
               | worrying about kilobytes seems misguided.
        
             | sesm wrote:
             | React exists because Facebook needed to sync DOM elements
             | in different parts of webpage with a single source of
             | state. There is still no global standard that solves this
             | problem.
        
               | gedy wrote:
               | Yeah I think some people glorify "simple", low level
               | solutions, which work fine for sprinkles of
               | interactivity. But if I'm building a non trivial UI
               | application - give me a framework please!
        
               | marcosdumay wrote:
               | You mean state handlers? Those are one of the main
               | reasons people adopted OOP at the 80's.
               | 
               | The observer pattern got pretty much standardized by the
               | GoP book, but people overwhelmingly prefer to run some
               | non-standard specialized thing, as it's usually much
               | simpler. It's a pretty much solved problem since way
               | before a lot of current developers were even born.
               | 
               | All of (ok, a lot of) the React's complexity comes from
               | it being a generic library that must support every kind
               | of usage. Any standard would have to be as complex.
        
               | reactordev wrote:
               | BS there's custom elements and classes and the ability to
               | target them with a selector. This is standard now. Web
               | components.
        
               | nicoburns wrote:
               | Web components don't really do the same thing. If you use
               | web components then you still need to manage the DOM
               | manually.
        
               | MrJohz wrote:
               | Web components solve encapsulation of structure, style,
               | and behaviour within a single component, but they don't
               | solve the larger state problems, because web components
               | don't come with any sort of state management beyond what
               | you can do with normal Javascript.
               | 
               | React does provide components, but there's not so much
               | different in React components than any other component
               | system. The main reason to use React is the state
               | management it provides on top of those components, making
               | sure that state is in sync across the whole application.
               | 
               | In my experience, the hard part of larger applications is
               | that handling of application state. Rendering data can be
               | done in umpteen different ways, and they're all pretty
               | much good enough, but handling application state in such
               | a way that every component remains in sync with all other
               | components is hard.
        
             | wayfinder wrote:
             | No, React exists because there was a need for a template
             | engine that's easy to use.
             | 
             | There is still no global standard for templates.
             | 
             | Just like mustache, Twig, Java Server Pages, Jinja, ERB...
             | every language has this problem. You have a bunch of
             | components written in HTML and you need to mix and match
             | them together in a bigger unit. React+JSX let you do that
             | easier than appending DOM components. Before React, you'd
             | use different libraries that did what React did.
             | 
             | The ONLY major language I can think of that has templating
             | baked in is PHP.
        
               | Joeri wrote:
               | HTML has built-in templates now, and custom elements (web
               | components) provide composability. If the built-in
               | templating is not quite powerful enough (it has no logic
               | or variables) there's developit/htm which is basically
               | JSX but parsing in the browser.
               | 
               | React is still easier, but it comes at a maintainability
               | tax because you have to keep upgrading to new react
               | versions and port to new react wrapper framework versions
               | if you want to keep a codebase in active development.
               | Vanilla web development has no such problem because web
               | standards remain backwards compatible.
               | 
               | For a small project where I don't care about SEO /
               | server-side rendering I absolutely prefer vanilla web dev
               | over React now.
        
               | wayfinder wrote:
               | Yes, it does! But while I have not used them yet, the
               | approach used by them (via SGML tags) is not new and many
               | libraries / XLST have done it before in the past 20+
               | years and I find the approach usable at best. It's too
               | verbose for my taste and it never really caught on, and I
               | find it hard to think that it would catch on this time.
        
               | nicoburns wrote:
               | > React is still easier, but it comes at a
               | maintainability tax because you have to keep upgrading to
               | new react versions and port to new react wrapper
               | framework versions if you want to keep a codebase in
               | active development.
               | 
               | There has been one breaking version of React (the recent
               | React 18) in it's 8 years of history. Upgrading React
               | versions is a non-issue.
               | 
               | Wrapper frameworks like next.js can come with a much
               | higher maintenance cost, but you don't need to use those
               | to use React (and I think most people don't).
        
               | johnmaguire wrote:
               | > The ONLY major language I can think of that has
               | templating baked in is PHP.
               | 
               | Depends on what you mean exactly. For example, Go ships
               | with templates. They don't mix HTML markup and Go code
               | directly though.
        
             | efdee wrote:
             | No, jQuery existed for that reason. React has other
             | reasons, one of them being that manual DOM tracking and
             | manipulation is brittle and annoying and the way React
             | works turns that around completely.
             | 
             | I'm not sure what Preact or NakedJSX offers me that would
             | make it a better choice than React.
        
               | reactordev wrote:
               | We don't do manual dom tracking anymore. We have custom
               | tags, shadow dom, es modules, etc making React obsolete.
        
         | hombre_fatal wrote:
         | Nothing in TFA competes with a web client framework, though,
         | since the framework is solving the general questions of how to
         | manage state and then update the UI when state changes.
         | 
         | For example, pretty much all of the TFA examples are code you'd
         | have to write even if you were using React.
        
       | jeffgreco wrote:
       | This looks like some helpful refreshers as I try and mess with
       | building a browser extension.
        
       | mg wrote:
       | These days, I get by with just two dependencies. One is dqs.js:
       | 
       | https://github.com/no-gravity/dqs.js
       | 
       | Which turns document.querySelector('.some .thing') into
       | dqs('.some .thing').
       | 
       | The other one is Handlebars:
       | 
       | https://github.com/handlebars-lang/handlebars.js/
       | 
       | Which I use for all my frontend templating needs.
        
         | dylan604 wrote:
         | are we really concerned about the shortness of the code for the
         | worse tradeoff of being less readable?
         | 
         | how much is truly saved by this? these seem like the things of
         | a solo dev vs building something for other people to follow
        
           | mg wrote:
           | What's wrong with solo devs?
           | 
           | You are talking to me on a site done by one.
           | 
           | This is the frontend code:
           | 
           | https://news.ycombinator.com/hn.js
        
             | evbogue wrote:
             | hn would benefit from the ael library
        
             | throw555chip wrote:
             | That's wild, never really looked into it, reminds me how a
             | C programmer thinks. I'm mostly backend but get involved
             | with frontend every now and then. Tried to avoid Angular
             | and React but now trying to teach myself Angular. AngularJS
             | was nice. Angular sucks, very complicated for doing the
             | same things I can do with vanilla HTML/CSS/JS, but that's
             | what companies seem to be hiring for.
        
             | dylan604 wrote:
             | I've been a solo dev as well. But unless you're going to
             | live forever, the code should be maintainable by someone
             | else. You can be a solo dev that's impossible to ever work
             | with, or you can maintain good practices so that other
             | people can play along as well.
        
             | deathanatos wrote:
             | ... is that a good example?
             | 
             | ... upvote/downvotes are does by fetching an "image", i.e.,
             | it does a GET request _with side-effects_! ... also seems
             | like a trivial CSRF vuln, too...
        
           | von_lohengramm wrote:
           | There's a reason why web developers have the reputation they
           | do.
        
         | evbogue wrote:
         | Combine this with https://github.com/dominictarr/hscrpt and
         | you'll be building websites in no time!
        
         | bambax wrote:
         | Instead of importing dsq you can do this
         | const $ = document.querySelector.bind(document);         const
         | $$ = document.querySelectorAll.bind(document);
        
           | mg wrote:
           | That's what I did before I put those lines (and some more)
           | into dqs.js
        
           | throw555chip wrote:
           | That's a neat shortcut, I prefer vanilla JS too.
        
           | gmiller123456 wrote:
           | That's pretty much what that include file does, but with
           | "dqs" rather than "$". I'm not a fan of using the $ as it
           | might confuse others that you're using JQuery.
        
             | bambax wrote:
             | Wouldn't that be a feature? ;-)
        
             | chrismorgan wrote:
             | $ is what I would expect and prefer, because it's what I've
             | been using in my browser dev tools for over fifteen years
             | (ah, Firebug; fond reminiscences). If your document doesn't
             | use the names, you'll get implementations roughly
             | equivalent to these:                 function $(selector,
             | element = document) {           return
             | element.querySelector(selector);       }
             | function $$(selector, element = document) {
             | return Array.from(element.querySelectorAll(selector));
             | }
             | 
             | Reference on more magic available in the console (there's a
             | lot of good stuff):
             | 
             | * https://firefox-source-docs.mozilla.org/devtools-
             | user/web_co... (I think ":help" is my new favourite: opens
             | that URL, which is not particularly discoverable)
             | 
             | * https://developer.chrome.com/docs/devtools/console/utilit
             | ies...
        
           | xeckr wrote:
           | Or
           | 
           | const $ = (query) => document.querySelector(query);
           | 
           | const $$ = (query) => document.querySelectorAll(query);
           | 
           | (How do I write monospace on HN?)
        
             | bambax wrote:
             | > _How do I write monospace on HN?_
             | 
             | Line that start with four spaces                   like
             | this
        
               | xeckr wrote:
               | Looks like 2 spaces are sufficient. But I sympathize with
               | 4-space indentation.
        
               | bambax wrote:
               | Indeed! I've always thought it was 4, because...
               | Markdown, probably?
        
             | chrismorgan wrote:
             | > _(How do I write monospace on HN?)_
             | 
             | Two-space indentation.
        
               | xeckr wrote:
               | Thank you
        
           | crtasm wrote:
           | Is there a way to make this also work as a function? e.g.
           | myTable.$$('tr').foreach()
        
             | mg wrote:
             | import {qsA} from './dqs.js';              rows =
             | qsA(myTable, 'tr');
        
               | crtasm wrote:
               | Thanks but the point is being able to chain it:
               | 
               | myTable.qsA('tr')
               | 
               | TypeError: myTable.qsA is not a function
        
               | mg wrote:
               | Well, since html elements already have a querySelectorAll
               | function, you could just assign it to a new method "qsA":
               | HTMLElement.prototype.qsA =
               | HTMLElement.prototype.querySelectorAll;
               | 
               | Now myTable.qsA('tr') will work. You can try it right
               | here on the HN page in the browser console:
               | HTMLElement.prototype.qsA =
               | HTMLElement.prototype.querySelectorAll;
               | document.querySelector('#hnmain').qsA('tr');
               | 
               | Why do you prefer chaining?
        
               | crtasm wrote:
               | Perfect, thankyou!
               | 
               | I suppose habit plus I find it easier to grok in that
               | order, targetelement->childelements->foreach.
        
               | xeckr wrote:
               | You'll have to do this in addition to one of the
               | previously discussed solutions if you want something like
               | document.qsA since document isn't an HTMLElement.
        
         | r-spaghetti wrote:
         | Can you use Handlebars in Cloudflare workers? EJS was not
         | accepted and string literals are string literals.
        
           | mg wrote:
           | handlebars.js runs in the browser:
           | 
           | https://plnkr.co/edit/LXb5TOMoyAxdbTxB
        
         | nicoburns wrote:
         | These days? This is what we were using 10 years ago before
         | React came about! It works fine, but performance can be a
         | problem in large apps as handlebars just naively recreates
         | entire DOM trees rather than diffing.
        
       | danielvaughn wrote:
       | So I'm working on this side project. I don't have a name for it
       | yet but I've been describing it as "vim for web designers". The
       | idea is that you can build a website (or components) in the
       | browser, similar to Webflow, but it's entirely driven by a
       | command language.
       | 
       | When I began the project, I told myself I wasn't going to use a
       | framework. After all, I've been doing this since 2009, I was
       | working with JS for a long time before I ever touched a
       | framework. And besides, the native DOM APIs have long been good
       | enough. Right?
       | 
       | My god, it was an absolute slog. Marshalling data into and out of
       | the DOM is so tedious and error prone that I began writing my own
       | mini framework to save my own sanity. And then I remembered why I
       | began using frameworks to begin with - because ultimately you're
       | going to be using a framework of some kind regardless, it's just
       | whether you want your own custom one or a community-built
       | industry standard.
       | 
       | I do still think native DOM is great, if you're working with
       | small amounts of interactivity. Most sites that use React
       | probably don't need it. But if your product has even a little bit
       | of nuance or complexity, I'd go with a framework and avoid the
       | hassle.
       | 
       | In the end I migrated to Svelte, and I'm much happier as a
       | result.
        
         | bryancoxwell wrote:
         | How's that saying go? Choose a framework or you'll invent one?
        
           | danielvaughn wrote:
           | Yep, and it's exactly right. It had been so many years since
           | I'd worked directly at the DOM layer that I'd forgotten why I
           | stopped.
           | 
           | That being said, it was equally difficult picking a framework
           | that had the least likelihood to handicap me down the road.
           | And I am still using plenty native methods, especially for
           | the CSSOM. That has yet to be sufficiently abstracted into
           | any kind of framework.
        
         | synergy20 wrote:
         | sveltekit is all about SSR these days, svelte itself does not
         | have a default client side router, I was trying svelte for csr
         | spa and gave up
        
           | danielvaughn wrote:
           | I'm using Astro for SSR and only using Svelte for the client-
           | side state. It's working out well so far.
        
           | meiraleal wrote:
           | With the view transition API[1], directory/index.html is/will
           | be the client-side router.
           | 
           | 1. https://chipcullen.com/adding-view-transitions-api/
        
         | dmix wrote:
         | Hyper minimalist projects always end up re-implementing half of
         | jquery or lodash. Much easier to just find a good library that
         | does treeshaking like ramda and use it sparingly.
        
           | Klonoar wrote:
           | I will gladly reimplement half of those projects if it means
           | I can avoid the JS build systems that break when I come back
           | and try to build in a year.
           | 
           | And to be fair I'm sure the build systems have gotten better
           | - they just all left a bad taste in my mouth. I spent more
           | than enough time working with them, writing plug-ins, etc.
        
             | danielvaughn wrote:
             | This was one of the reasons I really tried to go native.
             | Once you introduce a build system, it has to be maintained.
             | 
             | I eventually did choose Svelte, but I'm dockerizing it so I
             | can still use the thing a year from now, unlike virtually
             | all of my other projects.
        
         | the__alchemist wrote:
         | You are building application - I could estimate from your
         | description alone that you're better off wrapping the DOM
         | interactions.
         | 
         | For websites that need interaction, DOM manipulation is IMO a
         | better move due to it using a more fundamental/universal skill,
         | light or no build process, faster execution, and explicitness.
         | 
         | This is a _categorization_ , with lots of room for grey areas!
         | I bring it up because your use case falls squarely in the
         | category that benefits from a framework.
        
           | danielvaughn wrote:
           | Yeah, agreed. I was hoping I could lean into a quasi-HATEOAS
           | approach, where the state of the editor is reflected in the
           | state of the html output. My thinking was that if it's only
           | in the html, then in theory it would handle very large
           | numbers of nodes better, since you don't have to
           | correspondingly increase the size of JS object in memory.
           | 
           | I'm still attracted to that idea, but it's not worth it in
           | the short term.
        
       | marban wrote:
       | All good except for _Create a custom scrollbar_
        
       | beardyw wrote:
       | I am a great fan of vanilla JavaScript so for me it is a great
       | resource. Sadly many js developers nowadays don't really
       | understand what the Dom can do for them. A great resource!
        
       | bobmaxup wrote:
       | If I were making a cookbook on HTML/JS I would probably leave out
       | this:
       | 
       | https://phuoc.ng/collection/html-dom/sanitize-html-strings/#...
        
         | panzi wrote:
         | `value.startsWith('javascript:')` and there you have a
         | vulnerability. There can be arbitrary white-space before the
         | URL, so you'd need to do
         | `value.trim().startsWith('javascript:')` instead. However, I
         | much prefer white listing instead, i.e. only allowing `http:`,
         | `https:` and maybe `mailto:`, `ftp:`, `sftp:` and such. Maybe
         | allow relative URLs starting with `/`. Maybe. Though that would
         | mean to correctly handle all attributes that actually can be
         | URLs. Again, I'd just white list a few tags plus a few of their
         | attributes.
        
         | zeroCalories wrote:
         | Why? This is a common need. Is there an issue with the
         | implementation or another reason why you would want to use a
         | library?
        
         | chrismorgan wrote:
         | I'm not sure quite why you're against removing script tags, but
         | honestly that entire article is poor, riddled with disastrously
         | bad advice:
         | 
         | * "Using regular expressions": it suggests that this approach
         | is acceptable within its limits. It's not _at all_. As a simple
         | example, the expression shown is trivially bypassed by
         | "<script>...</script >". This is why, unlike the post claims
         | claims, using regular expressions for cleaning HTML is _not_ a
         | common approach.
         | 
         | * ("Eliminating the script tags": I want to grumble about using
         | `[...scriptElements].forEach((s) => s.remove())` instead of
         | `for (const s of scriptElements) { s.remove(); }` or even
         | `Array.prototype.forEach.call(scriptElements, (s) =>
         | s.remove())`. Creating an array from that HTMLCollection is
         | just unnecessary and a bad habit.)
         | 
         | * "Removing event handlers": `value.startsWith('javascript:')
         | || value.startsWith('data:text/html')` is inadequate. Tricks
         | like capitalising and adding whitespace (which the browser will
         | subsequently normalise) in order to bypass such poor checks
         | have been common for _decades_.
         | 
         | * "Retrieving the sanitized HTML": you are now vulnerable to
         | mXSS attacks, which undo all your effort.
         | 
         | * "Elements and attributes to remove from the DOM tree": this
         | proposes a blacklist approach and mentions _a few examples_ of
         | things that should be removed. Each example misses adjacent but
         | equally-important things that should be removed. You _will not_
         | get acceptable filtering if you start from this approach.
         | 
         | * "Simplifying HTML sanitization with external libraries": this
         | is pitched merely as easier, faster and cheaper, rather than as
         | the _only_ way to have any confidence in the result.
         | 
         | * "Conclusion": as I hope I've shown, "The DOMParser API is one
         | tool you can use to get the job done right." is not an
         | acceptable position.
         | 
         | Really, the article could be significantly improved by
         | presenting it as what a common developer might think, and then
         | scribbling all over the problematic things with these
         | explanations of why they're so bad, and ending with the
         | conclusion "so: just use the DOMPurify library; consider
         | nothing else acceptable". (There have at times been a couple of
         | other libraries of acceptable quality, but as far as I'm
         | concerned, DOMPurify has long been the one that everyone should
         | use. I note also that this article is talking about _client-
         | side_ filtration. I'm not familiar with the state of the art in
         | server-side HTML sanitisation, where you probably don't have an
         | actual DOM; this is also a reasonable place to wish to do
         | filtering, but the remaining active mXSS vectors might pose a
         | challenge. I'd want to research carefully before doing
         | anything.)
         | 
         | I look forward to the Sanitizer API
         | <https://wicg.github.io/sanitizer-api/> being completed and
         | deployed, so that DOMPurify can become just a fallback library
         | for older browsers.
        
           | bobmaxup wrote:
           | > I'm not sure quite why you're against removing script tags
           | 
           | My bad, I left a fragment in the URL.
        
       | cmrdporcupine wrote:
       | Nice. Bookmarked. Another good one in a similar vein is
       | https://youmightnotneedjquery.com/
       | 
       | I don't do web stuff often, but when I do I am _completely_
       | demoralized by the state of framework-itis there. It 's gotten
       | completely out of control. A fresh React project is hundreds of
       | dependencies. The weight of that complexity is astounding to me.
       | 
       | Meanwhile the core cross-platform browser tech shipped by default
       | has never been more capable and the amount of code to do common
       | things ... isn't very much.
       | 
       | Front-end devs: are you ok?
        
         | danielvaughn wrote:
         | Agreed it's out of control. But in the past year I've
         | transitioned to a platform team so I'm working with devops-ish
         | tooling for the first time. Holy shit...the amount of
         | complexity there gives front-end a run for its money. You've
         | got Kubernetes, Helm, Terraform, CircleCI, yadda yadda. The
         | amount of layered terminology in just those technologies alone
         | is absurd.
        
           | throw555chip wrote:
           | As a mostly backend dev, maybe I'm biased but all the tech
           | you listed there isn't layers of stuff. Each of those do
           | something different. For all but FAANG, kube is overkill.
           | Helm is just templating. The rest existed before DevOps was a
           | term.
        
             | cmrdporcupine wrote:
             | Was replying saying mostly this. I stay away from most of
             | that kind of stuff and work in embedded-type space mostly,
             | but when I have ventured in there, it all kind of makes a
             | certain amount of sense as modules that layer _relatively_
             | independent of each other. Because, well, most things
             | interoperate via Rest or gRPC or whatever, without a lot of
             | coupling.
             | 
             | The problem with the JS/TS/Node ecosystem is the _cultural_
             | tendency there to build and proselytize _frameworks_.
             | Heavily coupling seems to be seen as a positive rather than
             | negative.
        
         | mattlondon wrote:
         | I am no fan at all of react or npm, but some frameworks do
         | provide some helpful things that pure DOM APIs do not, so they
         | still have a place I think.
         | 
         | So e.g. application state management and routing are two huge
         | things you'll still need to implement yourself if you just use
         | pure DOM APIs
         | 
         | Depending on the complexity of your app then that might not be
         | such a big deal, but these extras are rapidly worth their
         | weight in gold as soon as you go beyond a basic app. Unless you
         | are using anything that needs NPM in which case you are fucked.
        
         | mablopoule wrote:
         | Another excellent resource in the same vein is the marvelous
         | https://javascript.info/
         | 
         | As a front-end dev who actually like the fundamental platform
         | and the capacities it offers, I'm both happy to see so much
         | nice things coming our way (nested CSS, container queries, and
         | a generally nicer JS experience since ES6) and at the same time
         | horrified by the amount of people using components for trivial
         | things like buttons or bold text.
         | 
         | And I do like framework, but so much framework and library's
         | marketing depend on making people believe that CSS and vanilla
         | DOM manipulation is insanely hard (it's not once you know the
         | fundamentals), and that pulling a random package on NPM is not
         | just quick and easy, but also _the professional thing to do_.
        
         | troupo wrote:
         | > Meanwhile the core cross-platform browser tech shipped by
         | default has never been more capable and the amount of code to
         | do common things ... isn't very much.
         | 
         | Have you tried to use this "capable cross-platform tech" to do
         | anything non-trivial? And React isn't the only thing out there.
        
       | panzi wrote:
       | `value.startsWith('javascript:')` and there you have a
       | vulnerability. There can be arbitrary white-space before the URL,
       | so you'd need to do `value.trim().startsWith('javascript:')`
       | instead. However, I much prefer white listing instead, i.e. only
       | allowing `http:`, `https:` and maybe `mailto:`, `ftp:`, `sftp:`
       | and such. Maybe allow relative URLs starting with `/`. Maybe.
       | Though that would mean to correctly handle all attributes that
       | actually can be URLs. Again, I'd just white list a few tags plus
       | a few of their attributes.
        
         | simonw wrote:
         | You mean from this article "Sanitize HTML strings"?
         | https://phuoc.ng/collection/html-dom/sanitize-html-strings/
         | 
         | Yeah, that article really shouldn't imply that sanitization is
         | "that easy". It does at least mention
         | https://github.com/cure53/DOMPurify at the end but it should
         | LOUDLY argue against attempting to write this particular thing
         | yourself and promote that exclusively in my opinion.
         | 
         | Filed an issue about this here:
         | https://github.com/phuocng/html-dom/issues/281
        
           | runarberg wrote:
           | There is also a future way of doing this with vanilla
           | JavaScript using the Sanitize API. It is enabled under flags
           | in most browsers currently.
           | 
           | https://developer.mozilla.org/en-
           | US/docs/Web/API/HTML_Saniti...
        
         | jfhr wrote:
         | Unless you need to support ancient browsers [1], I'd go the
         | easy way and leave the URL parsing to the browser, e.g.
         | `['http:', 'https:', 'mailto:', 'tel:'].includes(new URL(value,
         | location.origin).protocol)`
         | 
         | [1] https://caniuse.com/url
        
           | keepamovin wrote:
           | JavaScript elegance is always welcome!
        
       | fatnoah wrote:
       | What's old is new again. My first front-end role was building web
       | applications wayyyyy back in 1999. Everything was done with
       | "Vanilla" JS, including fancy stuff like drag and drop in a
       | treeview, click to edit, building what effectively was a single
       | page app, etc. etc. The hardest part was negotiating the
       | differences between Netscape and Internet Explorer.
        
       | kossTKR wrote:
       | Great resource! I've defaulted to just use vanilla js and petite-
       | vue, it's 15 kilobytes and gives a good base.
       | 
       | The problem is the build requirements you run into quickly if you
       | want to use plugins these days with vanilla js.
       | 
       | Elegance was being able to load actual modules from a CDN. Why
       | did we need these anti-web build steps on top of JS?
       | 
       | I feel like there was a sweet spot of complexity around Vue 1 or
       | say 2014.
       | 
       | The Vue 2-->3 jump illustrates the welcome but total breakdown of
       | frameworks in my opinion. It constantly gets in your way and
       | moving data on a page with a hierarchy you need some bizarrely
       | complex data flow, so many folders, files, tools, brittle
       | typescript linting, "auto" this and that, constant building and
       | so many rules it's not fun to engineer anymore.
       | 
       | Anyway, i think we are very close to a sweet spot if we just use
       | something like Petite-vue / Alpine on top of JS maybe with a tiny
       | router and get creative with JS around that, or just early
       | versions say Vue if we need anything more complex.
        
         | athanagor2 wrote:
         | The toolchain complexity problem was already present with Vue 2
         | (and anyway it was usable as a dependency pulled into a classic
         | web page). It definitely could be better, and it seems to be on
         | the way of being improved.
         | 
         | I feel like a lot of criticism toward Vue 3 is based on
         | feelings and vibes. What exactly are your complaints toward v3?
        
       | flanbiscuit wrote:
       | Seems like a helpful list of things to know, I haven't gone
       | through it all but looks good so far.
       | 
       | Clicked on the first one and I noticed something.
       | 
       | They write this:                 const setFavicon = () => {
       | const favicon = document.querySelector('link[rel="icon"]');
       | favicon.href = (window.matchMedia('(prefers-color-scheme:
       | dark)').matches)                         ? 'dark-mode-
       | favicon.png'                         : 'light-mode-favicon.png';
       | };            setFavicon();
       | 
       | And then this:
       | 
       | > We can use this function to update the user's color scheme
       | preference whenever they make a change.                 window
       | .matchMedia('(prefers-color-scheme: dark)')
       | .addEventListener('change', setFavicon);
       | 
       | They are running "window.matchMedia('(prefers-color-scheme:
       | dark)')" twice unnecessarily. If you're going to run `setFavicon`
       | as the callback to the event listener, you can get the result
       | from the `event` parameter passed to the callback like this:
       | const setFavicon = (event) => {           const favicon =
       | document.querySelector('link[rel="icon"]');
       | favicon.href = event.matches ? 'dark-mode-favicon.png' : 'light-
       | mode-favicon.png';
       | 
       | This would be my preferred way of doing it because it supports
       | users who are visiting with JS disabled.                 <link
       | href="light-mode-favicon.png" rel="icon" media="(prefers-color-
       | scheme: light)">       <link href="dark-mode-favicon.png"
       | rel="icon" media="(prefers-color-scheme: dark)">
       | 
       | https://phuoc.ng/collection/html-dom/change-the-favicon-dyna...
        
         | explaininjs wrote:
         | Also, doing it in HTML prevents the flash of alternate-themed
         | content. Doing the same with the `theme-color` meta is also a
         | seldom-used but great feature for detail-minded PWA developers.
        
       | alin23 wrote:
       | yeaaaaaaah no. Never going this path again for any interactive
       | page.
       | 
       | This summer I built an irrigation system for my father's field,
       | with the idea that the scheduling would be done in relative time
       | (water this zone for 2h) instead of absolute (start watering this
       | zone at 9AM and end at 11AM).
       | 
       | I kept it as simple as possible:                   - 16 cheap
       | relays for the 24V AC electric valves         - 1 beefy relay for
       | the pump          - 1 Pi Pico W for controlling the relays
       | 
       | Here's a picture of the "low-tech" build:
       | https://files.alinpanaitiu.com/lowtech-irigation.jpeg
       | 
       | The Pico W would have a _code.py_ with all the relay and schedule
       | logic, and an _index.html_ which would be a simple list of
       | sliders to set how much time each valve should be open. The Pico
       | W would function as a  "hotspot" which the phone would connect
       | to, and the "app" would be available at 192.168.4.1.
       | 
       |  _It can be added to homescreen and it looks just like a native
       | app as far as my father is concerned. It doesn 't feel like one
       | though, he can tell._
       | 
       | The web page looks like this: https://shots.panaitiu.com/lHMGplFn
       | 
       | That's all there is to it, really. That _simple_ single page with
       | a few sliders and buttons took weeks to build and test thoroughly
       | with only vanilla JS. I was obviously constrained by the flash
       | memory, but there are KB-sized helper frameworks nowadays which I
       | wasn 't aware of.
       | 
       | It's also really hard to refactor. I initially stored the
       | schedules at minute-resolution, but then had to store it in
       | second-resolution to add a _repeat schedule_ feature. Oh boy, so
       | much code to parse and change, so many slider.value calculations
       | to redo... yep, never doing this again
        
         | explaininjs wrote:
         | The magic of react is that it handles the entire View part of
         | MVVC and also provides a nice DSL for writing the View
         | Controller. With a lot of architectural planning you can
         | develop as clean of code without it (cleaner, perhaps), but I
         | agree it's better to just embrace it.
        
         | TheRealPomax wrote:
         | If you want to use the browser as a user interface for an
         | application, use a user interface library. Knowing what you're
         | building is just as important as picking the right tools after
         | you figured that part out: not all web pages (in fact, _man_
         | web pages) are not, and don 't need to be, user interfaces for
         | applications.
        
         | topspin wrote:
         | Is the code shared anywhere? I'm thinking that it could benefit
         | from some input from others that have done a lot of vanilla
         | JavaScript work. That application should be pretty concise and
         | DRY using <template>.
        
       | throw555chip wrote:
       | AI models will no doubt gobble it up and spit out back out in a
       | unique looking laundered format minus the comments.
        
       | est wrote:
       | Is there a CSS version of this? Like Zen-garden but modern
        
       | jampekka wrote:
       | I appreciate the benefit of not having dependencies but not a fan
       | of this rabid vanilla fixation.
       | 
       | Of course you can do anything with Vanilla that you can do with
       | e.g. jquery. Otherwise jquery obviously couldn't do it.
       | 
       | The problem is that the vanilla DOM API sucks.
       | document.getElementById sucks vs $, document.querySelector sucks
       | vs $. setTimeout and setInterval suck. addEventHandler really
       | sucks.
        
       | tolmasky wrote:
       | These are great. It's unfortunate that if there's any minor bugs
       | there's no way to really keep in sync though, for example the
       | security issue mentioned in another comment in these comments. It
       | would be cool if these examples could be wrapped up into some
       | sort of convenient "package" or something like that, such that
       | you could easily know if there are any updates and grab them, as
       | well as just make it easier to grab these functions whenever you
       | need them instead of copy-pasting them...
        
       | wangii wrote:
       | so, after 10 years of reactjs, we've forgot how to do this in
       | javascript?
        
       | agumonkey wrote:
       | Very nice list, it's nice to "down to earth" after too much react
       | ui libs :). Thanks.
        
       | blablabla123 wrote:
       | What really blew my mind was when I found out that many of the
       | DOM functions return live HTMLCollections that are automatically
       | updated. I wonder how often that feature is being actively used
       | in production code (before the framework craze or developing with
       | no framework being somewhat more popular again)
        
       | selimnairb wrote:
       | In Capitalist America, DOM manipulates you!
        
       | sumoboy wrote:
       | Same developer who has offers a form validator, very solid and
       | was worth the $ for past projects. Nice list of JS snippets.
        
       | bakkoting wrote:
       | A number of these are using older, awkward APIs, when there's
       | nicer native versions now.
       | 
       | For example, "replace an element" is
       | ele.parentNode.replaceChild(newEle, ele);
       | 
       | but unless you're targeting Chrome < 54, FF < 49, or Safari < 10,
       | you can just do                   ele.replaceWith(newEle)
       | 
       | `replaceWith` also lets you replace a node with _multiple_ nodes,
       | or with text.
       | 
       | Similarly, "loop over a nodelist" wants you to use array spread
       | and then forEach, instead of just                   for (let ele
       | of nodelist) ...
        
         | akira2501 wrote:
         | Good to keep in mind that nodelist is a live object. So
         | manipulating that list while looping over it can yield
         | surprising results.
        
       | DerekBickerton wrote:
       | For syntactic DOM manipulation sugar I use Cash[0]
       | 
       | [0] https://kenwheeler.github.io/cash/
        
       | throwaway858 wrote:
       | The technique for "Make a textarea auto-expand" is obsoleted by a
       | new CSS property("form-sizing"):
       | 
       | https://chriscoyier.net/2023/09/29/css-solves-auto-expanding...
       | 
       | Even without using this new CSS property, the technique that is
       | used (adjusting the "height" of the element) is not ideal and can
       | be glitchy.
       | 
       | A better approach is to use a mirror hidden element:
       | 
       | https://css-tricks.com/the-cleanest-trick-for-autogrowing-te...
        
       | earthboundkid wrote:
       | https://phuoc.ng/collection/html-dom/resize-an-iframe-to-fit...
       | 
       | There should be a way to do this with CSS and maybe some magic
       | headers. It's super annoying that it has be done via JS.
        
       | purplecats wrote:
       | what is the value in manually processing knowledge bases like
       | this (besides perhaps in an artisan fashion) if your knowledge
       | interface such as chatgpt already knows it and surfaces it at
       | will?
        
         | kavaruka wrote:
         | ChatGPT is useful only if you understand the code that it
         | produces
        
         | spacechild1 wrote:
         | You can ask the same question about any knowledge base. Why
         | here? This is completely off topic.
        
       | russellbeattie wrote:
       | My new favorite bit of vanilla JavaScript has been around since
       | Chrome 1.0 and IE: Element.insertAdjacentHTML. To say it's useful
       | is an understatement, especially with multi-line Strings using `.
       | I can't believe it's been around so long and I only realized it a
       | year or so ago.
       | 
       |  _The insertAdjacentHTML(position, text) method of the Element
       | interface parses the specified text as HTML or XML and inserts
       | the resulting nodes into the DOM tree at a specified position._
       | 
       | A contrived example of something that's a pain to do with raw
       | DOM:                   let anchors = ['#a', '#b', '#c'];
       | let el = document.querySelector('ul');         for (let a of
       | anchors) {           el.insertAdjacentHTML(
       | 'beforeend',             `<li><a
       | href="${a}">${a.substr(1)}</a></li>`           );         }
       | 
       | Previously I would have to create the li element, then the a
       | element, add it as a child, set the href attribute, then the text
       | value of the a element, then insert it into the ul element. Or,
       | I'd batch it all up as a big string and insert it using
       | innerHTML. Modifying an existing list was even more painful and
       | verbose.
       | 
       | 1. https://developer.mozilla.org/en-
       | US/docs/Web/API/Element/ins...
        
       ___________________________________________________________________
       (page generated 2023-11-06 21:01 UTC)