heyoffline: a small vanilla JS warning for a dropped network
Warn your users when their network goes down. Make sure they don't lose anything.
At a glance
- What is it?
- Heyoffline puts a modal in front of your user when the network disappears, and it has one option that matters more than the rest, monitorFields, which limits the warning to pages where the user has actually modified a form field. It is framework-agnostic vanilla JavaScript with no dependencies, and it ships as a UMD bundle and an ES module.
- Who is it for?
- Adopt heyoffline if you have a form driven web application where a user losing their connection should be told before they keep typing, and if you are happy with a dependency free script that renders its own modal. Do not adopt it as a general offline strategy, since it warns and does not queue work, and do not adopt it expecting it to detect a server side outage.
- Can I use it commercially?
- Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
- Is it still maintained?
- Yes. The repository last received commits 141 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What the library actually does
The repository description is the whole pitch in two sentences. Notify your users when their network goes down, and make sure they don't lose anything.
The feature list is three entries. It notifies on a general network outage. It can notify only when users have unsaved form field states. And it comes with default, pretty generic, good looking styles, with a screen recording in the README showing what that looks like.
That is a small library with a small job, and the design reflects that. The requirements section says Heyoffline is framework-agnostic vanilla JS, and the source code section says that all efforts have been made to keep the source as clean and readable as possible. There is no dependency in the runtime dependency list at all, which is unusual for a package published to npm and unusual in a good way for something that gets dropped into a page.
The package is MIT licensed, the version in package.json is 2.0.2, the author is Oskar Krawczyk, and the last push was on 2026-06-04. The repository has no GitHub releases, so the npm version is the version of record.
What it is not is an offline application framework. There is no queue, no retry, no caching of the user's work and no service worker. It warns a user and it tells your code when the network state changed. The promise of making sure they do not lose anything is fulfilled by interrupting them at the right moment, not by storing their input for them.
monitorFields is the option that changes the behaviour
The options table is where this library earns its place, and one entry is more important than the rest.
monitorFields is a boolean that defaults to false, and when it is enabled the message on network error will be shown only if an input, textarea, select or similar element on the page was modified. The default is a warning on any outage, and the option narrows it to the case where the user actually has something at stake.
The fields option controls what counts as a field, and its default is the CSS selector "input, select, textarea, *[contenteditable]", which covers ordinary form controls and also editable regions. The example in the setup section shows the narrower form of it:
new Heyoffline({
monitorFields: true,
fields: ".monitoredFields"
});That example is worth reading twice, because it shows the intended use. Rather than monitoring every input on the page, you mark the ones that matter with a class, and the warning only appears when one of those has been touched. On an application with a search form in the header and a large settings form in the body, that is the difference between a warning that is always in the way and one that appears at the right moment.
The remaining options are presentation and control. prefix is a string, defaulting to heyoffline, which is the class prefix for the generated elements, so a page with two instances can style them apart. noStyles, a boolean defaulting to false, tells the library not to use the default CSS, which is generated by JS. And disableDimiss, a boolean defaulting to false, hides the dismiss button, so that the user cannot wave the warning away when they have unsaved work.
Two ways to load it, module or script tag
The setup section gives one path for a bundler and one for a plain page.
For a module, the package is on npm as heyoffline, and the example imports the ES module build directly and constructs the instance:
import Heyoffline from "./dist/heyoffline.esm.js"
new Heyoffline()The manifest explains the file layout. The main field points at dist/heyoffline.umd.js, the module field at dist/heyoffline.esm.js, and the browser field also points at the UMD build, so a bundler and a script tag resolve to the same artefact by default.
For a page without a build step, the browser route uses UNPKG:
<script src="dist/heyoffline.umd.js"></script>and then the instance is constructed with its options.
Note what the constructor call does not take. There is no configuration of where to mount the modal, no target element, and no callback for the user clicking the dismiss button. The library generates its own elements with the prefix class and injects its own styles, which is the reason the noStyles option exists, and the reason the prefix option exists. If your application needs the warning to appear inside a specific container, or to look like the rest of your design system, the library is going to fight you rather than help you, because it owns the markup and the CSS.
The text options cover the whole message
Four options control what the user reads, and they are all strings or an icon.
text.offline.title is the heading of the modal window, defaulting to "You're currently offline". text.offline.content is the body message, defaulting to "Wait until your network comes back before continuing." text.offline.button is the dismissal button label, defaulting to "Dismiss". And text.offline.icon is the modal icon, whose default is an SVG icon.
The fact that the icon is described as an SVG rather than a path or a URL tells you something about how the library is built. The styles are generated by JavaScript, and the README says the library is released under an MIT License, so do with it what you will. The default appearance is meant to be a complete, self contained thing.
That approach is right for a library whose whole purpose is to be dropped into somebody else's page in five minutes, and it is the reason the noStyles option is there. If you set noStyles to true, you get the modal and the behaviour with no styling at all, which means you have to write the CSS for the generated elements yourself, and you need to know the class names, which is what the prefix option lets you control.
One small flaw in the documentation is worth noting because it affects anyone integrating it. The README has two sections titled Requirements, one stating that the library is framework-agnostic vanilla JS and one stating the licence. And the option that hides the dismiss button is spelled disableDimiss, with two s characters where you would expect one. Both are things a reader will hit in the first ten minutes.
The two events, and the question the README leaves open
The events table lists two.
onOnline fires then the network becomes available, and onOffline fires when the network disappears.
Those are the hooks you use to do something in your own code, and the naming is worth checking against your framework's conventions, because a method called onOnline is a callback rather than a subscription in the usual event emitter sense, and the README does not describe how you attach it.
The more interesting gap is the detection mechanism. The README describes when the events fire, and it says the library notifies on a general network outage, but it does not say how the outage is determined. The browser's own connectivity events are the obvious candidate, and if that is what is used then the semantics are those of the browser rather than of your application. That distinction matters in two situations that a connectivity event gets wrong: a captive portal or a hotel wifi where the network is up and the internet is not, and a backend that is down or slow while the user's connection is fine.
In both cases the browser still believes it is online, so a warning driven by a connectivity event would stay silent while the user's request hangs. The library is a good fit for the case it is named for, a connection that genuinely drops, and the documentation does not make any claim beyond that, but it is the thing to test first if your users are on flaky or proxied networks.
The build is rollup, and the dev dependencies are unpinned
The build story is short. The scripts are start, which is gulp watch, and build, which is rollup --config rollup.config.js, with the rollup configuration and the gulpfile in the repository alongside src/ and dist/.
Two things about the development dependencies are worth noticing, because they are the kind of detail that decides whether a project still builds in two years. The dev dependency list is browser-sync, bs-snippet-injector, gulp, fs and rollup, and every one of them is pinned to the string "latest" rather than to a version range. A build that resolves the newest version of each tool every time is a build that can break without anything in the repository changing, and the fs package, which exists to give browserify access to Node's file system, is an unmaintained approach to that problem.
For a library whose runtime has no dependencies at all, that is an odd place to be loose, and it is the clearest signal about the project's maintenance state. The last push was on 2026-06-04, the package version is 2.0.2, and there are no GitHub releases to fall back on.
None of that affects the artefact you would consume, since the published package is a built bundle and does not need the toolchain. It does affect anyone who wants to build it from source, and that is the right thing to know before forking it.
Editorial conclusion
Adopt heyoffline if you have a form driven web application where a user losing their connection should be told before they keep typing, and if you are happy with a dependency free script that renders its own modal. Do not adopt it as a general offline strategy, since it warns and does not queue work, and do not adopt it expecting it to detect a server side outage. Verify first how the outage is detected, because the README documents the events but not the mechanism, and that matters for captive portals and for a backend that is down while the browser still believes it is online.
Frequently asked questions
How do I install and use heyoffline?
The package is on npm as heyoffline. In a module build, import Heyoffline from "./dist/heyoffline.esm.js" and call new Heyoffline(). In a plain page, include the UMD build with a script tag pointing at dist/heyoffline.umd.js.
What does the monitorFields option do?
It is a boolean that defaults to false. When enabled, the message on network error is shown only if an input, textarea, select or similar element on the page was modified. The fields option, defaulting to "input, select, textarea, *[contenteditable]", decides which elements are watched.
Can I hide the dismiss button and restyle the modal?
Yes. The disableDimiss option, spelled with two s characters in the README, hides the dismiss button so the user cannot wave the warning away. The noStyles option stops the library from injecting its default CSS, and the prefix option, defaulting to heyoffline, sets the class prefix used for the generated elements.
What events does heyoffline provide?
Two. onOnline fires when the network becomes available, and onOffline fires when the network disappears. The README does not document how the outage is detected, only when these events fire.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/oskarkrawczyk-heyoffline)Was this useful?