Show HN: Minimalist editor that lives in browser, stores everything in the URL
321 points
by medv
13 hours ago
| 53 comments
| github.com
| HN
I wanted to see how far I could go building a notes app using only what modern browsers already provide – no frameworks, no storage APIs, no build step.

What it does:

Single HTML file, no deps, 111 loc

Notes live in the URL hash (shareable links!)

Auto-compressed with CompressionStream

Plain-text editor (contenteditable)

History support

Page title from first # heading

Respects light/dark mode

No storage, cookies, or tracking

The entire app is the page source.

https://textarea.my/

gnyman
11 hours ago
[-]
Funny how I made almost exactly the same but for maps.

I needed a way to share a link to a map, with drawings and the ability for the receiver to see their own location on the map.

Annotated screenshots solves the first but not the second.

Vibe engineered this, with many of the same ideas as OP.

Took an evening. Just in time apps for one specific use case is a thing.

And because it's so cheap to make and can be hosted cheaply with no backend, it can be given away for free.

https://nyman.re/mapdraw/#l=60.172108%2C24.941458&z=16&d=LU8...

reply
zenmac
18 minutes ago
[-]
Great tool! There is a little issue with the +/- zoom buttons not working something cause it is over layed by other div blocks. On mac firefox.

Is the code open source online somewhere?

reply
mathgeek
10 hours ago
[-]
> Vibe engineered

While I'm all for vibe coding as appropriate, there's a lot of humor to be found it calling it engineering. :D

reply
block_dagger
10 hours ago
[-]
Fair. Though it seems that half of engineering is just giving a respectable name to whatever actually works.
reply
mathgeek
10 hours ago
[-]
For software, but that's a well trodden path at this point. I've seen a few projects that are actually "vibe engineering" outside of software on the 3d modeling side so the terms are confusing.
reply
antman
2 hours ago
[-]
That is absolutely great! Using it now to plan a trip.

Could we also add text annotations? Also the delete button could delete just the last shape or a selected shape so as not to start over?

reply
blntechie
3 hours ago
[-]
This is so cool!! The responsiveness of the page is so much better than any maps app I have used.
reply
nextaccountic
5 hours ago
[-]
This is pretty cool!

And if you are open to bug reports.. if I move around the drawings move smoothly with the map, but if I zoom in/out the drawings move only after the map zooming animation ends, rather than smoothly

reply
RandomDistort
10 hours ago
[-]
Is this open source?
reply
Gehinnn
10 hours ago
[-]
This is very cool!
reply
roxolotl
12 hours ago
[-]
Was just working on something similar this morning. As an fyi you can avoid the string replacing in the base64 string by using `.toBase64({ alphabet: "base64url" })` and `fromBase64({ alphabet: "base64url"})`.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...

reply
maxloh
13 hours ago
[-]
Per the spec [0], a URL can hold at least 8,000 characters.

> It is RECOMMENDED that all senders and recipients support, at a minimum, URIs with lengths of 8000 octets in protocol elements. Note that this implies some structures and on-wire representations (for example, the request line in HTTP/1.1) will necessarily be larger in some cases.

Mainstream browsers support at least 64,000 characters [1], and Chrome supports up to 2MB [2].

[0]: https://www.rfc-editor.org/rfc/rfc9110#section-4.1-5

[1]: https://stackoverflow.com/a/417184/

[2]: https://chromium.googlesource.com/chromium/src/+/HEAD/docs/s...

reply
medv
13 hours ago
[-]
Chrome limit is 2MB, Firefox is 1MB, WebKit is no limit.

Here is the Crime and Punishment by Fyodor Dostoevsky:

- https://medv.io/goto/crime-and-punishment-by-fyodor-dostoevs...

reply
maxloh
12 hours ago
[-]
For what it's worth, there might be a 2GB limit on the iOS side.

https://github.com/swiftlang/swift-corelibs-foundation/blob/...

reply
caminanteblanco
1 hour ago
[-]
This unfortunately immediately crashed my android firefox nightly browser. Amusingly it loaded the page, but one click on the address bar sent me straight to the home screen
reply
spicyusername
7 hours ago
[-]
Incredible.

My absolute favorite thing about modernity is how enabled we are to riff on a riff of a riff.

In 1346, if a blacksmith came up with something cool, its quite possible that it died with them.

reply
gchamonlive
10 hours ago
[-]
Interesting, in Firefox mobile (actually fennec) if I tap the address bar, I get an empty text box.

EDIT: actually I can edit the URL, but it takes a while to load.

reply
oneseven
8 hours ago
[-]
hmmm makes me wonder if you could train llms on gzipped text. would save a lot of tokens that way.
reply
scotty79
12 hours ago
[-]
Works fine on Win11 Edge
reply
hallole
12 hours ago
[-]
LOL Tapping the address bar crashed my Chrome on mobile.
reply
lurking_swe
11 hours ago
[-]
loaded OK for me on mobile safari.
reply
kylecazar
11 hours ago
[-]
Loaded fine for me too -- but like parent, tapping the address bar to share afterwards crashed it on Android here :)
reply
nosrepa
10 hours ago
[-]
My Firefox on mobile seemingly handled it fine.
reply
berkes
12 hours ago
[-]
I guess the surveillance industry has enough incentives to make this ever larger, so they can fit more utm-trackers, campaign-ids, referal trackers and whatnot in URLs.

It's truly insane how large typical share-URLS for content on instagram, youtube or any other large platforms are. URLs that could've been example.com/t/some-large-enough-id?time=13337 are stuffed with hundreds of characters, just to gather more data on people using these links.

reply
dspillett
12 hours ago
[-]
> Per the spec [0], a URL can hold at least 8,000 characters.

> It is RECOMMENDED that all senders and recipients support, at a minimum, URIs with lengths of 8000 octets in protocol elements.

It is always worth remembering that, unless you have already ensured that the content has been rendered into a URI-safe subset of ASCII, a character and an octet are not the same thing.

reply
ghurtado
12 hours ago
[-]
Very good point indeed. In the worst case scenario, you would only have 1/5th of that capacity
reply
ngc6677
9 minutes ago
[-]
reply
gabrielsroka
8 hours ago
[-]
I did something similar with a spreadsheet years ago. It's lkudgy, but it works. You have to tab away from the input box and refresh the page, iirc.

https://gabrielsroka.github.io/webpages/calc.htm#a1:=Rate=3....

  https://gabrielsroka.github.io/webpages/calc.htm#a1:=Rate=3.875;a2:=Years=30;a3:=NPer=Years*12;a4:=PV=644000;a5:=Pmt=Math.round(Math.pmt(Rate/12/100,NPer,PV)*100+1)/100;rows:5;cols:1
More examples https://gabrielsroka.github.io/webpages/

It's about 130 js loc

reply
rfl890
7 hours ago
[-]
You claim no tracking, and yet there's a Cloudflare Web Analytics beacon placed at the bottom of the page (thankfully filtered out by uBlock Origin)
reply
growt
12 hours ago
[-]
I recently build a small framework to create JavaScript apps that use this kind of URL sharing and therefore don’t require a backend: https://github.com/grothkopp/lost.js
reply
levmiseri
11 hours ago
[-]
I really like this from a privacy point of view. So much so that I'm thinking about adding a purely URL-storage solution as an option in my https://kraa.io editor.
reply
omoikane
10 hours ago
[-]
From a privacy point of view, you might not want to use textarea.my since it includes some tracking bits at the end:

    <script defer src="https://static.cloudflareinsights.com/beacon.min.js/vcd15cbe7772f49c399c6a5babf22c1241717689176015" integrity="sha512-ZpsOmlRQV6y907TI0dKBHq9Md29nnaEIPlkf84rnaERnq6zvWvPUqr2ft8M1aS28oN72PdrCzSjY4U6VaAw1EQ==" data-cf-beacon='{"version":"2024.11.0","token":"6a22b097a2b44fa4af0a95817ce96ab5","r":1,"server_timing":{"name":{"cfCacheStatus":true,"cfEdge":true,"cfExtPri":true,"cfL4":true,"cfOrigin":true,"cfSpeedBrain":true},"location_startswith":null}}' crossorigin="anonymous"></script>
reply
WD-42
11 hours ago
[-]
From a privacy point of view how is it any better than just using a local, native text editor?
reply
levmiseri
10 hours ago
[-]
From purely privacy point of view it’s not. But if you also want markdown features, custom typography and easy sharing, this starts to make more sense.
reply
nickweb
12 hours ago
[-]
Think you've inadvertently found a way to provide extra tests for mobile devices.

The Crime and Punishment one consistently crashes Brave mobile for me. I assume it's the length of the URL - and seen another commentator say the same for chrome mobile (sure they both use the same codebase so likely an upstream issue).

reply
ctenb
13 hours ago
[-]
I made something similar once, specifically targetted for guitar tablature https://tabviewer.app/ To make links shorter for sharing with others, I use a shortlink service. Pasting URLs of thousands of characters long can be problematic
reply
planb
12 hours ago
[-]
Wow funny I‘m just seeing this after posting my tab editor in another comment. I have the same use case as you :)

https://github.com/planbnet/guitartabs

reply
surrTurr
11 hours ago
[-]
shameless plug: i built something very similar but nobody cared: https://github.com/AlexW00/Buffertab
reply
antman
2 hours ago
[-]
Voice typing is a cool feature, have you considered whisper wasm instead of OpenAI api?
reply
samcollins
13 hours ago
[-]
Nice! I made a similar thing but the html for the text editor fits in a data uri, so it can be a bookmark or new tab page for taking quick notes

https://gist.github.com/smcllns/8b727361ce4cf55cbc017faaefbb...

reply
meander_water
4 hours ago
[-]
Cool project, but loading "Crime and Punishment" crashed my mobile browser.

I don't think urls were built for that kind of punishment.

reply
greggman65
10 hours ago
[-]
I have something tangentially similar here: https://jsgist.org

If you click save you get the option to use a URL.

The problem with a URL every edit is a new URL. So you send the URL to a friend, then fix a typo, they need a new URL.

The other problem is of course the space limit.

reply
jerrygoyal
3 hours ago
[-]
I too built a one (text is stored in localstorage)

https://gourav.io/devtools/notepad

reply
billforsternz
12 hours ago
[-]
This is very interesting, very refreshing, very simple and clever, very well done, very everything good. Bravo and thank you.
reply
zkmon
2 hours ago
[-]
Why store in the URL and make it bloated? Isn't storing in local storage enough?
reply
medv
13 hours ago
[-]
In case you missed it: it is possible to style textarea via CSS and share it.

- https://textarea.my/#TYuxDcIwEEWpmeKUCiSIJQoKU0KFRBUWOGwnWDi...

reply
Yash16
3 hours ago
[-]
I like this because most of the time I need random stuff—numbers, quick searches, or ideas—and this helps instantly.
reply
frizlab
7 hours ago
[-]
> Respects light/dark mode

Not really… using js to change the CSS on the go is not a good practice. Why does it matter? Because of the “dark mode” browser extensions. They often use the presence of @media query (or other standard CSS means of setting dark mode colors), and if it’s the JS that changes the colors we often get partial Dark Mode, which does not work at all.

reply
medv
2 hours ago
[-]
No js is used for colors.
reply
codazoda
12 hours ago
[-]
Nice! I love this.

I built Ponder in the same vein. It, however, has 10 files. I did not use the URL, did not have double the fun, and now I’m sad.

https://github.com/codazoda/ponder

reply
bdcravens
4 hours ago
[-]
I keep this in the bookmark bar for the times I need a place to paste a quick bit of text (but it doesn't persist):

data:text/html, <html contenteditable>

reply
lifthrasiir
1 hour ago
[-]
Use xem's version [1] if you need persistence:

    <body id=b contentEditable onload=b[i="innerHTML"]=[(l=localStorage).c] oninput=l.c=b[i]>
[1] https://xem.github.io/postit/
reply
valgaze
8 hours ago
[-]
Brings this to mind: https://hashify.me/IyBUaXRsZQ==
reply
zX41ZdbW
9 hours ago
[-]
I've implemented the same idea a few years ago: https://pastila.nl/
reply
medv
2 hours ago
[-]
It uses DB at the backend.
reply
wwarren
13 hours ago
[-]
Amazing. The crime and punishment example crashed my iPhone’s Google Chrome when I tap the URL haha
reply
spacedoutman
8 hours ago
[-]
Seems like we have all built something similar.

hopefully mine can stand out with all the extra features i have managed to cram in

reply
thelastgallon
5 hours ago
[-]
I wonder if this can be paired with a local URL shortener? Chaining this with a local URL shortener can mean access to any doc with a single letter (or very letters).
reply
planb
12 hours ago
[-]
A few weeks ago I vibe coded a guitar tab editor just because I wanted to share a quick tab in a chat group with my band. When the first prototype already worked great, I just couldn’t stop to add features so that it now even has mouseover chord diagrams and copy and paste.

The sharing works just like here, by encoding the tab itself in the url.

https://github.com/planbnet/guitartabs

reply
marcuskaz
13 hours ago
[-]
I have a similar one using localStorage https://github.com/mkaz/browser-pad
reply
ljlolel
12 hours ago
[-]
I love this.

Now if you bootstrap the app code into the url too then you can have a minimal kernel to run any machine in url.

Then you can also make a Quine somehow.

reply
cantalopes
7 hours ago
[-]
I feel this is more of a fun toy project because if i used it every day my browser history cache and browser performance would get annihilated
reply
mixedmath
11 hours ago
[-]
I wrote a similar app when mathbin was shutting down. It allows about 1500 characters of mathjax-displayed notes. [1]

[1]: https://davidlowryduda.com/mathshare/

reply
huhtenberg
11 hours ago
[-]
In Firefox, https://textarea.my shows up as as a completely static non-actionable white page. Just white, with default cursor. No errors on the console.
reply
pglevy
12 hours ago
[-]
Thanks for sharing! I tried a similar content-in-url approach for a family grocery list app but I couldn't get the url that short. (It worked but it was a bit cumbersome sharing over Whatsapp.) Will see what I can learn from this!
reply
gisho
11 hours ago
[-]
I created a similar app just 2 days ago targeting Whatsapp (https://linqshare.com) . Context: In my locality, EA, we normally have Whatsapp groups raising funds for whatever reason; for every content edit, the admin has to copy-edit-paste updated content(which contains name and amount) to the group. This small app intends to provide a table that's easy to convey this info. App stores content in the url but a preview image (needed for Whatsapp share) is stored at R2. Let me know if you want the source code running at Cloudflare.

--edit-- test link: https://linqshare.com/#eJxtkM9KxDAQxl-lzLmHrv8Ova3IHlz04BY8F...

reply
sltkr
10 hours ago
[-]
Something similar by Eric Wastl (of Advent of Code fame): https://topaz.github.io/paste/
reply
urbandw311er
9 hours ago
[-]
Neat. But why would you auto-set the title from markdown heading syntax when it doesn’t support markdown? (Or any rich text in fact)
reply
medv
2 hours ago
[-]
You can still write markdown. Nobody prevents you.
reply
WhyIsItAlwaysHN
11 hours ago
[-]
My own plug, translate between SQL dialects, state stored in URL so you can share it:

https://sqlscope.netlify.app/

reply
nemtsv
10 hours ago
[-]
I think a couple of days ago I stumbled upon your editor in corp Google intranets when I was looking for internal tool to pretty print some json, small world :)
reply
medv
2 hours ago
[-]
The http://go/fmt-err? =) Yes, it is mine.
reply
reconnecting
11 hours ago
[-]
Are <head>, <body>, and </html> missing intentionally?

Safari 15.6.1: Unhandled Promise Rejection: ReferenceError: Can't find variable: CompressionStream

reply
wdporter
11 hours ago
[-]
I probably shouldn’t presume to speak for the OP, but given that they’re optional, I would think so, yes.
reply
qbane
13 hours ago
[-]
Just started making my own recently with CodeMirror 6 during holidays. No saving function for now: https://qbane.github.io/cgm
reply
nvahalik
13 hours ago
[-]
Love your other tools, btw!
reply
medv
13 hours ago
[-]
Thanks!
reply
theoa
9 hours ago
[-]
This hack has completely disrupted my afternoon! Perhaps even forever after.
reply
srexrg
2 hours ago
[-]
this is indeed minimalistic :)
reply
jaysonelliot
12 hours ago
[-]
546,229 character-length URL for the Crime and Punishment example.

Half a megabyte for a URL. That certainly is a thing.

reply
xeonmc
13 hours ago
[-]
Can you make it monospace by default, so that this can be used as a code snippet bin?
reply
medv
12 hours ago
[-]
Sure! textarea.my support custom style attr: https://textarea.my/#Ky4tSlVUyCotLlEoLUhJLElVKC6pzElVSCwpKWJ...
reply
throwaway150
12 hours ago
[-]
How do you share after that? I can open devtools and change the attribute but the URL doesn't update after that.
reply
medv
2 hours ago
[-]
Update the text a bit to trigger save event.
reply
adamschwartz
13 hours ago
[-]
reply
edgars_xx
13 hours ago
[-]
love it, funny enough, I had similar idea pop into my head some weeks ago, just to be able to store quick notes and favorite them in my browser for later
reply
LordDragonfang
12 hours ago
[-]
It would be neat if ctrl+s offered to download the textarea to a .txt file.
reply
desireco42
12 hours ago
[-]
The only thing missing is markdown and few themes. I think this is awesome idea for sharing. Love what you did with it.
reply
ThrowawayTestr
12 hours ago
[-]
reply
teach
12 hours ago
[-]
reply
medv
12 hours ago
[-]
reply
RonanSoleste
10 hours ago
[-]
reply
mzelling
13 hours ago
[-]
Love it!
reply
deafpolygon
13 hours ago
[-]
Can you save anything?
reply
rorylawless
13 hours ago
[-]
reply
sltkr
11 hours ago
[-]
reply
RonanSoleste
10 hours ago
[-]
reply
thomascgalvin
13 hours ago
[-]
Not OP: sure, just bookmark it
reply
tony_cannistra
13 hours ago
[-]
kinda -- but then you have to re-bookmark it every time you update it...
reply
medv
13 hours ago
[-]
It also saves to localStorage
reply
rane
11 hours ago
[-]
Now what if it didn't pollute browser history
reply
sublinear
12 hours ago
[-]
I like these kinds of projects, but adding a file export/import is inevitable. It's less about the limits of a URL and more about practicality.

I also have no way to confirm that URLs aren't logged server side, so I'd never trust the claim about "no tracking". That's why these projects also end up self-hosted.

reply
denisinvader
12 hours ago
[-]
hash part of url only available in the browser, as far as I know, server doesn’t have access to # value
reply
jamesdwilson
11 hours ago
[-]
very easy for the server to intentionally (or by compromise) add a one liner to send the hash text up.
reply
sublinear
12 hours ago
[-]
Typos and URL mangles are common though, and I'd still have no way to confirm if it got logged in that case. It's out of scope for anything in the github source, and instead depends on the server hosting the page. I know this isn't meant to be super secure, but it's still worth a mention.
reply
throwaway150
12 hours ago
[-]
Typos aren't making the hash part turn into something else. Like your parent comment explained to you, the hash part is not sent to the server. If you go out of your way to mangle the URL then of course a mangled URL without hash will likely get logged to the server. But I'm not sure how one would manage to go so much out of the way that they mangle the URL in a way that removes the hash.
reply
sublinear
10 hours ago
[-]
You don't have a choice pasting links into some apps. They may strip out query and hash components, percent encode, force URL shortener services, etc.

Percent encoding is particularly bad since it may also bloat the length causing truncation and the decompress to fail. There's endless footguns with URLs.

reply