Documentation

Progressive Web App (PWA) Support

Add offline support, service workers, and installability with PWAMixin

Canonical documentation is on docs.djust.org

This local page is a lightweight reference and fallback. The complete guide — with tutorials, theming, code examples, and more — lives on our dedicated docs site.

View on docs.djust.org

Progressive Web App (PWA) Support

djust provides built-in PWA support for offline-first applications with automatic synchronization, service worker generation, and offline-aware template directives.

What You Get

  • Service worker integration -- Automatic caching of HTML responses and static assets
  • Offline state management -- IndexedDB/LocalStorage abstraction via mixins
  • Optimistic UI updates -- Immediate feedback with sync when online
  • Offline directives -- dj-offline-hide, dj-offline-show, dj-offline-disable
  • Automatic manifest generation -- PWA manifest with customizable settings

Quick Start

1. Enable PWA in Your Templates

{% load djust_pwa %}
<!DOCTYPE html>
<html>
<head>
    {% djust_pwa_head name="My App" theme_color="#007bff" %}
</head>
<body>
    {% djust_offline_indicator offline_text="You're offline" %}
    {% djust_offline_styles %}

    <div dj-offline-hide>Only shown when online</div>
    <div dj-offline-show>Only shown when offline</div>
    <button dj-offline-disable dj-click="submit">Submit</button>
</body>
</html>

2. Use PWA Mixins in Your Views

from djust import LiveView
from djust.pwa.mixins import PWAMixin, OfflineMixin

class MyView(OfflineMixin, LiveView):
    template_name = 'app.html'

    def mount(self, request):
        # No enable call: inheriting OfflineMixin is what enables offline mode.
        self.items = self.storage.get('items', [])

    def add_item(self, name):
        created = self.create_offline('Item', {'name': name})
        self.items.append(created)
        self.storage.set('items', self.items)
        self.sync_when_online()

3. Generate the Service Worker

python manage.py generate_sw

PWA Mixins

PWAMixin

Base mixin for PWA functionality:

MethodDescription
get_pwa_config()PWA config dict injected into the template context
register_pwa_handlers()Register the install/update event handlers
handle_install_prompt()Called when the install prompt is shown
handle_app_update(version)Called when a new app version is available

There is no enable_offline() / disable_offline() / is_offline_enabled() — inheriting the mixin is what turns the behaviour on.

OfflineMixin

Enhanced offline state management. It does not subclass PWAMixin — combine them explicitly (class V(OfflineMixin, PWAMixin, LiveView)) if you want both.

MethodDescription
storageProperty — the OfflineStorage instance (.get(key, default) / .set(key, value))
sync_queueProperty — the pending SyncQueue
create_offline(model, data)Queue a create for sync; returns the optimistic record
update_offline(model, obj_id, data)Queue an update for sync
delete_offline(model, obj_id)Queue a delete for sync
get_cached_or_fetch(key, queryset)Serve from cache, else evaluate the queryset
sync_when_online()Drain the sync queue
get_offline_state()Current offline state dict
is_online()Always True server-side — see the note below
handle_connection_change(online)Connection-change hook (no built-in caller)

There is no save_offline_state() / load_offline_state() / handle_online(); use the storage property directly.

SyncMixin

Automatic background synchronization. It does not subclass OfflineMixin, and it depends on storage / sync_queue being supplied by one — list it afterOfflineMixin (class V(SyncMixin, OfflineMixin, LiveView)), or the properties raise AttributeError.

MethodDescription
sync_queueProperty — the pending SyncQueue; enqueue via create_offline() / update_offline() / delete_offline()
sync_managerProperty — the SyncManager that runs the sync
sync_<verb>_<Model>(action_data)Your hook, e.g. sync_create_Item; case-sensitive (built as f"sync_create_{action.model}")

Template Tags

{% djust_pwa_head %}

Complete PWA setup in one tag (manifest + service worker registration):

{% djust_pwa_head name="My App" theme_color="#007bff" %}

{% djust_pwa_manifest %}

Generate the PWA manifest link:

{% djust_pwa_manifest name="My App" short_name="App"
   theme_color="#007bff" background_color="#ffffff" display="standalone" %}

{% djust_sw_register %}

Register the service worker:

{% djust_sw_register sw_url="/sw.js" scope="/" %}

{% djust_offline_indicator %}

Visual offline status banner:

{% djust_offline_indicator offline_text="You're offline" show_when="offline" %}

Offline Directives

DirectiveBehavior
dj-offline-hideHide element when offline
dj-offline-showShow element only when offline
dj-offline-disableDisable form element when offline
dj-offline-queuedNot implemented — no client code reads this attribute; listed here only so it is not mistaken for a working directive
<div dj-offline-hide>
    <button dj-click="save_to_server">Save</button>
</div>
<div dj-offline-show>
    <p>Changes will sync when you're back online.</p>
</div>

Service Worker Configuration

# settings.py
DJUST_PWA = {
    'MANIFEST': {
        'name': 'My Application',
        'short_name': 'MyApp',
        'theme_color': '#007bff',
        'background_color': '#ffffff',
        'display': 'standalone',
        'icons': [
            {'src': '/static/icons/icon-192.png', 'sizes': '192x192', 'type': 'image/png'}
        ]
    },
    'SERVICE_WORKER': {
        'CACHE_NAME': 'djust-v1',
        'STRATEGY': 'cache-first',  # or 'network-first'
        'URLS_TO_CACHE': ['/static/css/app.css', '/static/js/app.js'],
        'OFFLINE_URL': '/offline/',
        'EXCLUDE_PATTERNS': [r'/admin/', r'/api/websocket/']
    }
}

Example: Offline Todo App

from djust import LiveView
from djust.pwa.mixins import OfflineMixin

class TodoView(OfflineMixin, LiveView):
    template_name = 'todos.html'

    def mount(self, request):
        self.todos = self.storage.get('todos', [])

    def add_todo(self, text):
        todo = self.create_offline('Todo', {'text': text, 'done': False})
        self.todos.append(todo)
        self.storage.set('todos', self.todos)
        self.sync_when_online()

    def toggle_todo(self, todo_id):
        for todo in self.todos:
            if todo['id'] == todo_id:
                todo['done'] = not todo['done']
                self.update_offline('Todo', todo_id, {'done': todo['done']})
        self.storage.set('todos', self.todos)
        self.sync_when_online()

Management Commands

# Basic generation
python manage.py generate_sw

# Custom output path
python manage.py generate_sw --output static/custom-sw.js

# Include static file collection
python manage.py generate_sw --collect-static

# Custom version
python manage.py generate_sw --version 2.1.0

Adding PWA to an Existing App

  1. Add {% load djust_pwa %} to your base template
  2. Include {% djust_pwa_head %} in your <head>
  3. Mix PWAMixin or OfflineMixin into your LiveViews
  4. Run python manage.py generate_sw
  5. Deploy with HTTPS (required for service workers in production)

Browser Support

BrowserSupport
Chrome / EdgeFull
FirefoxFull
SafariPartial (no background sync)
Mobile SafariFull with install prompt

Best Practices

  • Service workers require HTTPS in production (localhost is exempt for development).
  • Use network-first strategy for dynamic content and cache-first for static assets.
  • Validate data in the sync queue before sending to the server.
  • Consider authentication token expiry when designing offline flows.
  • Test offline behavior in Chrome DevTools (Application > Service Workers > Offline).