Code Monkey home page Code Monkey logo

htmz's Introduction

htmz

a low power tool for html

htmz is a minimalist HTML microframework that gives you the power to create dynamic web user interfaces with the familiar simplicity of plain HTML.

Zero dependencies. Zero JS bundles to load. Not even a backend is required. Just an inline HTML snippet.

See the documentation website for more details, usage, examples, and more.

Installing

Simply copy the following snippet into your page.

<iframe hidden name=htmz onload="setTimeout(()=>document.querySelector(contentWindow.location.hash||null)?.replaceWith(...contentDocument.body.childNodes))"></iframe>

What does it do?

htmz does one thing and one thing only.

  • Enable you to load HTML resources within any element in the page.

Imagine clicking a link, but instead of reloading the whole page, it only updates a relevant portion of the page. Think tabbed UIs, dual-pane list-detail layouts, dialogs, in-place editors, and the like.

htmz is a generalisation of HTML frames. — Load HTML resources within any frame any element in the page.

htmz's People

Contributors

kalabasa avatar atmos4 avatar octopusinvitro avatar malix-off avatar mootookoi avatar tkdnbb avatar yuretz avatar

Stargazers

justin avatar Mitchell Johnson avatar Kaiden / GL avatar Evan Boehs avatar Vlad Lasky avatar Ed Saleh avatar Oliver Anteros avatar  avatar Eric Quanz avatar Simon avatar Thecode764[bot] avatar Matthieu Prat avatar Eric Bailey avatar Adrian D. Alvarez avatar devin ivy avatar maxdevjs avatar Igor Boldyrev avatar Eugene Metagnostic avatar  avatar  avatar Rafael Revi avatar  avatar Dmitry Marukov avatar Alessio Delmonti avatar Ivan Shabanov avatar Ryan Stafford avatar Karlin Fox avatar Eli Mellen avatar Gabriel Avila avatar Konstantin Taranov avatar twelve eighty pix. avatar  avatar Pawel Tolstoi avatar  avatar someson avatar Lukáš Kucharczyk avatar Evan Relf avatar Danny Kirkham avatar @MéSilicon7 avatar  avatar  avatar Niels Bom avatar Thiago Rodrigues Santos avatar Tarun Ramakrishna Elankath avatar Tobias Løfgren avatar Vladislav Borovikov avatar Michael Williams avatar  avatar Marc avatar Rob Mills avatar Nuno Sousa avatar Thanh Trần avatar Paul Esch-Laurent avatar  avatar Martijn van der Heijden avatar Kyle Chamberlain avatar Wilk avatar Maciej Olko avatar Melker Ulander avatar Kieran Wood avatar François Roucoux avatar Mario Penterman avatar Alice Lia Stapleton avatar  avatar Jan Deppisch avatar  avatar AhmedKaram avatar  avatar Ian Maleney avatar asiamoth avatar Not-Hegel avatar Kyle Jacobson avatar Power Snail avatar  avatar Sarfaraz Muhammad Sajib avatar Md. Shahinur Rahman avatar Michael Murphy avatar  avatar Markus Strasser avatar Hamzah Al-washali avatar Moisés Cruz avatar  avatar Moore Crest avatar  avatar Santhosh Thamaraiselvan avatar Luis Ch. avatar  avatar Taras Bratyshchenko avatar Jupiter Barrera avatar adachisan avatar Timon Böhler avatar  avatar Curie avatar jayssj11 avatar Declan L. Scott avatar Geraldo Castro avatar Yevhen Pavlov avatar Josué Díaz avatar Scott Aguila avatar Richard Zilahi avatar

Watchers

Abhik Khanra avatar Benjamin Thomas avatar ⊣˚∆˚⊢ avatar Hugh Barnes avatar Moisés Cruz avatar  avatar F.Baube avatar  avatar mos avatar jQueryScript avatar  avatar Louis Pilfold avatar Matjaž Potočnik avatar Mehdi avatar  avatar Hari R avatar

htmz's Issues

Is a no JS website possible with this if put thought some preprocessor (Speculation)

If I understand the snippet correctly, this search and replaces the doc and replace specific sections with a specially formatted iframe.

If that's the case, then in theory it could be possible to add a script to this htmz for static website generators to add some dynamic capabilities to their site (but without having to add JS code to it).

Application for this technique could be for torsites that should really not have javascript enabled.


You still want to keep the snippet as it makes things easier without having to integrate a preprocessor. But basically this would be an extra optional script in this repo that developers can optionally call. It would read a html input and scan for a htmlz snippet (to indicate it is being used) and then do the search and replace of required tags with an iframe) before outputting to stdio

Loader extension does not reflect request state properly

The loader extension is a bit too shallow: it will only show a loading spinner once the server has begun sending the first byte.

This means it is not a true loading indicator (like htmx's hx-indicator), which is fine but quite limiting in terms of functionality, especially when trying to mitigate the "laggy" feeling of hypermedia-driven applications.

(the loader extension also uses onload, which is deprecated. It should rather use onbeforeload).

I have two proposed solutions:

  • improve the extension to make it 1-1 with hx-indicator. This will involve more code and a custom attribute, so more complex overall.
  • leave the extension as is, and add "htmz vs htmx" examples.

What would you prefer? Depending on what you like best I can submit a PR!

What is the IFRAME advantage over shadowDOM?

With a <load-file> Web Component you have the choice of loading any content into DOM, or in shadowDOM to keep <style> scoped... and even move (global) style (or any Node for that matter) to shadowDOM
No need to define it before being used like your htmz function; any existing <load-file> will upgrade automagically.

/*
  defining the <load-file> Web Component,
  yes! the documenation is longer than the code
  License: https://unlicense.org/
*/
customElements.define("load-file", class extends HTMLElement {

  // declare default connectedCallback as async so await can be used
  async connectedCallback(
    // call connectedCallback with parameter to *replace* SVG (if <load-file> is not replaceWith)
    src = this.getAttribute("src"),
    // attach a shadowRoot if none exists (prevents displaying error when moving Nodes)
    // declare as parameter to save 4 Bytes: 'let '
    shadowRoot = this.shadowRoot || this.attachShadow({mode:"open"})
  ) {
      // load SVG file from src="" async, parse to text, add to shadowRoot.innerHTML
    shadowRoot.innerHTML = await (await fetch(src)).text()

    // append optional <tag [shadowRoot]> Elements from <load-file> innerHTML/lightDOM after parsed content
    shadowRoot.append(...this.querySelectorAll("[shadowRoot]"))

    // if "replaceWith" attribute exists
    // then replace <load-file> with loaded content <load-file>
    // childNodes instead of children to include #textNodes also
    this.hasAttribute("replaceWith") && this.replaceWith(...shadowRoot.childNodes)
  }
})

source: a DEV.to Post from 2021

Support IE 11

In order to support older browser such as IE 11, you could rewrite the onclick handler to:

setTimeout(function(){(document.querySelector(contentWindow.location.hash||null)||{}).outerHTML=contentDocument.body.innerHTML})

Using htmz without updating browser history

Hello!

Thanks for this library! It's very cool.

Do you have a recommendation or an extension for not adding to the browser history when clicking on htmz links? I'd like my back button to (for example) go to what my user sees as the previous page rather than resetting a form to a previous state.

Thanks,
Louis

Forms with list inputs & required

Hey Lean, firstly let me say fantastic project and such an inspiring use of the web. I can feel the future of web development starting to take shape!

Lots of tools I write are basically just forms. However, we can't write them with "just HTML" because we often need to input a list of elements, for example data like this:

{
  "firstName": "Angus",
  "hobbies": [ "cooking", "running" ] 
}

And a form that could submit this could look like this:

<form method='post' action='/submit'>
  <input name='firstName' value='Angus' required>
  <input name='hobbies[]' value='cooking'>
  <input name='hobbies[]' value='running'>
  <button id='add-hobby' formaction='/add-hobby'>add hobby</button>
  <input type='submit'>
</form>

This nearly works, but sadly not quite as the form must be valid before you can submit it.

Screenshot 2024-02-24 at 10 53 55

Can you think of a workaround for this? All I can think is:

  • Nested forms (disallowed)
  • Using a link instead of a button (can't be clicked twice in a row)
  • Just do all validation on the backend, and return a half-completed form in the case of errors (might actually be ok?)

I wonder if anyone has any ideas? Small forms like this are so close to being HTML only, but this list-of-inputs thing stops me every time - meaning I have to duplicate rendering code on the client (then I might as well just write everything client side).

Breaks links to subheadings

Many websites give their subheadings an id and then make it or a ToC link to the subheading. This allows to send a link to a specific subheading. Your script breaks that.

Clean target values approach not working

Using the htmz function defined in a script tag isn't working in either Chrome or Safari for me.

Code:

<iframe hidden src="/tasks/1#hello" id="hello" name=htmz onload="htmz(this)"></iframe>
<script type="text/javascript">
  function htmz(frame) {
    document.querySelector(frame.name) // use the iframe's name instead of the URL hash
      ?.replaceWith(...frame.contentDocument.body.children);
  }
</script>

Errors:

# Safari
TypeError: htmz is not a function. (In 'htmz(this)', 'htmz' is an instance of Window)
# Chrome
Uncaught TypeError: htmz is not a function
    at HTMLIFrameElement.onload

No Content Security Policy is being used. I'm not sure what could be wrong here. Any guidance?

Support for consecative GET requests to the same resource URL

The default htmz snippet doesn't support multiple requests to the same resource URL. There are a couple workarounds to this, one is to make resource URL unique with query parameters, but ideally htmz would just handle this out of the box and make the same request twice. Below is an example of how to achieve this.

<script>
function htmz(frame){
  setTimeout(()=>{
    if(frame.contentWindow.location=='about:blank') return; //Don't load blank page, and avoid infinite loop.

    document.querySelector(frame.contentWindow.location.hash||null)?.replaceWith(...frame.contentDocument.body.childNodes);
    
    frame.contentWindow.location='about:blank'; //clear iframe after load.
  })
}
</script>
<iframe hidden name=htmz onload="htmz(this)"></iframe>

Without setting the location to about:blank after the replacement, a link would only load once and consecative clicks would be ignored since the resourceURL didn't change.

Anyway, Not sure if this merits a example, or maybe there is a cleaner technique.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.