JurisJS Examples

Explore live demonstrations of JurisJS features with complete source code. Each example showcases the power of progressive enhancement with the enhance() API.

🔢 Simple Counter

Basic reactive state management with increment/decrement functionality using enhance() API

0
JavaScript
HTML
const app = new Juris();

// Enhance the display to show reactive counter value
app.enhance('#counter-display', (props, { getState }) => ({
    textContent: () => getState('counter', 0)
}));

// Enhance increment button
app.enhance('#counter-inc', (props, { getState, setState }) => ({
    onClick: () => setState('counter', getState('counter', 0) + 1)
}));

// Enhance decrement button
app.enhance('#counter-dec', (props, { getState, setState }) => ({
    onClick: () => setState('counter', getState('counter', 0) - 1)
}));

// Enhance reset button
app.enhance('#counter-reset', (props, { setState }) => ({
    onClick: () => setState('counter', 0)
}));
<div class="demo-counter">
    <div class="count-display" id="counter-display">0</div>
    <div>
        <button class="demo-button" id="counter-dec">- Decrement</button>
        <button class="demo-button" id="counter-inc">+ Increment</button>
    </div>
    <div>
        <button class="demo-button secondary" id="counter-reset">Reset</button>
    </div>
</div>

📝 Todo List

Dynamic list management with add, toggle, and delete operations using pure enhance() API

Learn JurisJS
Build amazing apps
JavaScript
HTML
const app = new Juris({
    states: { 
        todos: [
            { id: 1, text: 'Learn JurisJS', completed: false },
            { id: 2, text: 'Build amazing apps', completed: false }
        ]
    }
});

// Enhance todo checkboxes - Pure enhance() API!
app.enhance('.todo-checkbox', (props, { getState, setState }) => ({
    onClick: () => {
        const todoId = parseInt(props.element.dataset.id);
        const todos = getState('todos', []);
        const updated = todos.map(todo => 
            todo.id === todoId ? { ...todo, completed: !todo.completed } : todo
        );
        setState('todos', updated);
    },
    className: () => {
        const todoId = parseInt(props.element.dataset.id);
        const todos = getState('todos', []);
        const todo = todos.find(t => t.id === todoId);
        return `todo-checkbox ${todo?.completed ? 'checked' : ''}`;
    }
}));

// Enhance delete buttons - Clean and simple!
app.enhance('.todo-delete', (props, { getState, setState }) => ({
    onClick: () => {
        const todoId = parseInt(props.element.dataset.id);
        const todos = getState('todos', []);
        setState('todos', todos.filter(todo => todo.id !== todoId));
    }
}));

// Enhance todo items for completion styling
app.enhance('.todo-item', (props, { getState }) => ({
    className: () => {
        const todoId = parseInt(props.element.dataset.id);
        const todos = getState('todos', []);
        const todo = todos.find(t => t.id === todoId);
        return `todo-item ${todo?.completed ? 'completed' : ''}`;
    }
}));

// Add new todos on Enter
app.enhance('#todo-input', (props, { getState, setState }) => ({
    onKeyPress: (e) => {
        if (e.key === 'Enter' && e.target.value.trim()) {
            const newTodo = {
                id: Date.now(),
                text: e.target.value.trim(),
                completed: false
            };
            const todos = getState('todos', []);
            setState('todos', [...todos, newTodo]);
            e.target.value = '';
        }
    }
}));
<div class="todo-demo">
    <input type="text" class="todo-input" id="todo-input" placeholder="Add a new todo..." />
    <div class="todo-list" id="todo-list">
        <div class="todo-item" data-id="1">
            <div class="todo-checkbox" data-id="1"></div>
            <span class="todo-text">Learn JurisJS</span>
            <button class="todo-delete" data-id="1">Delete</button>
        </div>
        <div class="todo-item" data-id="2">
            <div class="todo-checkbox" data-id="2"></div>
            <span class="todo-text">Build amazing apps</span>
            <button class="todo-delete" data-id="2">Delete</button>
        </div>
    </div>
</div>

📋 Reactive Form

Real-time form validation and reactive output display with enhance() API

Fill in the form above to see reactive updates
JavaScript
HTML
const app = new Juris({
    states: { 
        form: { name: '', email: '' }
    }
});

// Enhance form inputs to update state
app.enhance('#form-name', (props, { setState }) => ({
    onInput: (e) => setState('form.name', e.target.value)
}));

app.enhance('#form-email', (props, { setState }) => ({
    onInput: (e) => setState('form.email', e.target.value)
}));

// Enhance output to show reactive form data
app.enhance('#form-output', (props, { getState }) => ({
    innerHTML: () => {
        const name = getState('form.name', '');
        const email = getState('form.email', '');
        
        if (!name && !email) {
            return 'Fill in the form above to see reactive updates';
        }
        
        const isValid = name && email && email.includes('@');
        return `
            <div>Name: ${name || 'Not provided'}</div>
            <div>Email: ${email || 'Not provided'}</div>
            <div>Status: ${isValid ? '✅ Valid' : '❌ Invalid'}</div>
        `;
    }
}));
<div class="form-demo">
    <div class="form-group">
        <label class="form-label">Name:</label>
        <input type="text" class="form-input" id="form-name" />
    </div>
    <div class="form-group">
        <label class="form-label">Email:</label>
        <input type="email" class="form-input" id="form-email" />
    </div>
    <div class="form-output" id="form-output">
        Fill in the form above to see reactive updates
    </div>
</div>

🎨 Theme Switcher

Dynamic styling based on reactive state changes using enhance() API

Current Theme

Click buttons below to change theme

JavaScript
CSS
const app = new Juris({
    states: { theme: 'dark' }
});

// Enhance theme demo container
app.enhance('#theme-demo', (props, { getState }) => ({
    className: () => `theme-demo ${getState('theme', 'dark')}`
}));

// Enhance theme display text
app.enhance('#theme-display', (props, { getState }) => ({
    textContent: () => `Active theme: ${getState('theme', 'dark')}`
}));

// Enhance theme buttons
app.enhance('#theme-light', (props, { setState }) => ({
    onClick: () => setState('theme', 'light')
}));

app.enhance('#theme-dark', (props, { setState }) => ({
    onClick: () => setState('theme', 'dark')
}));

app.enhance('#theme-auto', (props, { setState }) => ({
    onClick: () => setState('theme', 'auto')
}));
.theme-demo {
    padding: 2rem;
    border-radius: 12px;
    transition: all 0.3s ease;
}

.theme-demo.light {
    background: #f8fafc;
    color: #1e293b;
}

.theme-demo.dark {
    background: #1e293b;
    color: #e2e8f0;
}

.theme-demo.auto {
    background: linear-gradient(45deg, #f8fafc 50%, #1e293b 50%);
    color: #7c3aed;
}

🛣️ Simple Router

Client-side routing with dynamic page content using enhance() API

🏠 Home Page

Welcome to the home page! Click the navigation buttons above to see different pages.

JavaScript
Router Config
const app = new Juris({
    states: { currentRoute: 'home' }
});

const routePages = {
    'home': { icon: '🏠', title: 'Home Page', content: 'Welcome to the home page!' },
    'about': { icon: '📋', title: 'About Page', content: 'Learn more about our application.' },
    'contact': { icon: '📞', title: 'Contact Page', content: 'Get in touch with us!' },
    '404': { icon: '❌', title: '404 Not Found', content: 'Page not found.' }
};

// Enhance router content to show current page
app.enhance('#router-content', (props, { getState }) => ({
    innerHTML: () => {
        const route = getState('currentRoute', 'home');
        const page = routePages[route] || routePages['404'];
        return `
            <h4>${page.icon} ${page.title}</h4>
            <p>${page.content}</p>
        `;
    }
}));

// Enhance route buttons
app.enhance('#route-home', (props, { setState }) => ({
    onClick: () => setState('currentRoute', 'home')
}));

app.enhance('#route-about', (props, { setState }) => ({
    onClick: () => setState('currentRoute', 'about')
}));

app.enhance('#route-contact', (props, { setState }) => ({
    onClick: () => setState('currentRoute', 'contact')
}));

app.enhance('#route-404', (props, { setState }) => ({
    onClick: () => setState('currentRoute', '404')
}));

// Enhance buttons to show active state
app.enhance('.router-nav button', (props, { getState }) => ({
    className: () => {
        const currentRoute = getState('currentRoute', 'home');
        const buttonRoute = props.element.id.replace('route-', '');
        return buttonRoute === currentRoute ? 'active' : '';
    }
}));
// Advanced router configuration
const app = new Juris({
    router: {
        routes: {
            '/': 'HomePage',
            '/user/:id': {
                component: 'UserPage',
                guards: ['authGuard'],
                loadData: 'loadUserData'
            },
            '/admin': {
                component: 'AdminPage',
                guards: ['authGuard', 'adminGuard']
            }
        },
        
        guards: {
            authGuard: ({ getState, navigate }) => {
                if (!getState('user.isAuthenticated')) {
                    navigate('/login');
                    return false;
                }
                return true;
            },
            
            loadUserData: async ({ params, setState }) => {
                const userData = await fetchUser(params.id);
                setState('currentUser', userData);
            }
        }
    }
});

🌐 API Integration

Fetch and display data from external APIs with loading states using enhance() API

Click button to load a random fact
JavaScript
Service
const app = new Juris({
    states: { 
        apiData: null,
        isLoading: false,
        error: null
    },
    
    services: {
        apiService: {
            async fetchRandomFact({ setState }) {
                setState('isLoading', true);
                setState('error', null);
                
                try {
                    // Simulate API call
                    await new Promise(resolve => setTimeout(resolve, 1000));
                    const facts = [
                        "JurisJS is 8x faster than most popular frameworks",
                        "Progressive enhancement allows existing HTML to become reactive",
                        "JurisJS has zero dependencies and requires no build process"
                    ];
                    const randomFact = facts[Math.floor(Math.random() * facts.length)];
                    setState('apiData', { fact: randomFact });
                } catch (error) {
                    setState('error', 'Failed to fetch data');
                } finally {
                    setState('isLoading', false);
                }
            }
        }
    }
});

// Enhance fetch button
app.enhance('#fetch-data', (props, { services }) => ({
    onClick: () => services.apiService.fetchRandomFact({ 
        setState: app.setState.bind(app) 
    })
}));

// Enhance API content display
app.enhance('#api-content', (props, { getState }) => ({
    innerHTML: () => {
        const isLoading = getState('isLoading', false);
        const error = getState('error', null);
        const data = getState('apiData', null);
        
        if (isLoading) {
            return '<div style="color: #ffd700;">⏳ Loading random fact...</div>';
        }
        
        if (error) {
            return `<div style="color: #ef4444;">❌ ${error}</div>`;
        }
        
        if (data) {
            return `
                <div style="background: rgba(124, 58, 237, 0.1); padding: 1rem; border-radius: 8px; border: 1px solid rgba(124, 58, 237, 0.3);">
                    <strong>💡 Random Fact:</strong>
                    <p style="margin-top: 0.5rem; margin-bottom: 0;">${data.fact}</p>
                </div>
            `;
        }
        
        return 'Click button to load a random fact';
    }
}));
// Service-based API integration
const app = new Juris({
    services: {
        userService: {
            async getUser(id, { setState }) {
                setState('user.loading', true);
                
                try {
                    const response = await fetch(`/api/users/${id}`);
                    const user = await response.json();
                    setState('user.data', user);
                    setState('user.error', null);
                } catch (error) {
                    setState('user.error', error.message);
                } finally {
                    setState('user.loading', false);
                }
            },
            
            async updateUser(id, updates, { setState, getState }) {
                const currentUser = getState('user.data');
                setState('user.data', { ...currentUser, ...updates });
                
                try {
                    await fetch(`/api/users/${id}`, {
                        method: 'PUT',
                        headers: { 'Content-Type': 'application/json' },
                        body: JSON.stringify(updates)
                    });
                } catch (error) {
                    // Rollback on error
                    setState('user.data', currentUser);
                    setState('user.error', 'Update failed');
                }
            }
        }
    }
});

Ready to Build with JurisJS?

These examples showcase the power of the enhance() API for progressive enhancement. Static HTML becomes reactive with minimal, declarative code.

View Documentation Try Full Demo