Ad – 728Γ—90
πŸ¦‰ Interview Prep

OWL JS Practical Exercises – 12 Hands-On Challenges

Reading about OWL is not enough β€” you must build things. These 12 exercises progress from beginner to advanced, covering every section of the course. Each exercise specifies what to build, which OWL concepts to apply, and a set of acceptance criteria. Work through them in order: each one builds on the skills from the previous. By the end, you will have a portfolio of real OWL components ready to show at interviews.

⏱️ 6–10 hours total 🎯 Beginner β†’ Advanced πŸ“… Updated 2026

Beginner (Exercises 1–4)

Exercise 1 β€” Traffic Light (⭐ Beginner)

Build: A traffic light component that cycles through red β†’ yellow β†’ green β†’ red on click.

Concepts: useState, t-att-class, t-on-click, conditional classes

Acceptance criteria:

  1. Three colored circles rendered with CSS. Only the active one is "lit" (full opacity / glow).
  2. A "Next" button cycles the state. The sequence must be: red β†’ yellow β†’ green β†’ red.
  3. A text label below shows the current light name and the associated rule (Stop / Prepare / Go).
  4. Use t-att-class with an object for active/inactive state β€” do not use inline styles.
  5. Use a getter currentLight that returns the active light object from the state array.

Exercise 2 β€” Shopping Cart (⭐ Beginner)

Build: A product list + shopping cart with add/remove functionality.

Concepts: useState arrays, t-foreach, t-key, getters, state mutations, events in loops

Acceptance criteria:

  1. Hard-code 6 products in state: { id, name, price, category }.
  2. Render product cards in a grid using t-foreach. Each has an "Add to Cart" button.
  3. Cart shows items with quantity controls (+ / –) and a remove button per item.
  4. Cart total and item count are computed via getters and update reactively.
  5. Adding an already-carted product increases its quantity (no duplicates in cart).
  6. Quantity cannot go below 1 (the – button is disabled at 1; remove button deletes the item).

Exercise 3 β€” Multi-Step Form (⭐⭐ Beginner-Intermediate)

Build: A 3-step wizard form with validation at each step.

Concepts: t-model (all types), t-if/elif/else, form validation, useState, static props

Acceptance criteria:

  1. Step 1: Name (text, required), Email (email, required, valid format), Password (min 8 chars).
  2. Step 2: Date of birth (date input), Country (select with 5+ options), Newsletter checkbox.
  3. Step 3: Review β€” display all entered data read-only with an "Edit" link per step.
  4. Each step validates on "Next" click. Errors show inline. Cannot advance with invalid data.
  5. Progress bar shows which step is active/complete. Back button available from step 2+.
  6. Submit shows a success screen with a summary of entered data.

Exercise 4 β€” Filterable & Sortable Table (⭐⭐ Beginner-Intermediate)

Build: A data table with search, column sort, and pagination.

Concepts: useState, getters (computed), t-foreach, t-model, t-att-class, dynamic attributes

Acceptance criteria:

  1. Hard-code 20 employee records: { id, name, department, salary, joinDate }.
  2. A search input filters rows by name or department (case-insensitive, t-model.lazy).
  3. Click any column header to sort ascending; click again for descending. Show a β–²/β–Ό icon.
  4. Pagination: 5 rows per page. Show page X of Y. Previous/Next buttons disabled at limits.
  5. A getter chains filter β†’ sort β†’ paginate. All applied in correct order.
  6. Show "No results" when filters produce an empty set.
Ad – 336Γ—280

Intermediate (Exercises 5–8)

Exercise 5 β€” Component Library (⭐⭐⭐ Intermediate)

Build: A mini UI component library: Button, Input, Card, Modal, Badge.

Concepts: static props, defaultProps, slots, t-att-class, t-att-style, component composition

Acceptance criteria:

  1. Button: props for variant (primary/secondary/danger), size (sm/md/lg), disabled, loading. Full prop declarations.
  2. Input: props for type, label, placeholder, error message. Binds value via callback props (not t-model internally).
  3. Card: header, body (default), footer slots. All slots have fallback content.
  4. Modal: uses Card internally. Props: isOpen, onClose. ESC key closes it (global listener in onMounted/onWillUnmount).
  5. Badge: props for label, color, dot (boolean β€” shows a colored dot before label).
  6. Demo page renders all components with all prop variants in a gallery layout.

Exercise 6 β€” Custom Hooks Library (⭐⭐⭐ Intermediate)

Build: 5 custom hooks, each demonstrated in a component.

Concepts: Custom hooks, lifecycle composition, useState, onMounted, onWillUnmount

Acceptance criteria:

  1. useToggle(initial) β€” returns { value, on, off, toggle }. Demo: light switch UI.
  2. useCountdown(seconds) β€” counts down from N, stops at 0, returns { remaining, start, reset }. Uses setInterval with onWillUnmount cleanup. Demo: quiz timer.
  3. useLocalStorage(key, default) β€” persists state to localStorage. Demo: theme preference that survives page refresh.
  4. useWindowSize() β€” reactive { width, height }. Demo: show "mobile" / "tablet" / "desktop" based on width.
  5. useKeyboard(bindings) β€” accepts { "Ctrl+S": saveFn, "Escape": closeFn }. Adds/removes global keydown listener. Demo: shortcut help panel.

Exercise 7 β€” Real-Time Feed (⭐⭐⭐ Intermediate)

Build: A live activity feed that simulates real-time updates.

Concepts: onMounted/onWillUnmount, setInterval, scroll preservation (onWillPatch/onPatched), useRef

Acceptance criteria:

  1. In onMounted, start a setInterval that appends a new fake event every 2 seconds.
  2. Show maximum 50 events β€” splice older ones when limit is exceeded.
  3. Implement scroll preservation: if user is at the bottom, auto-scroll to new items. If scrolled up, preserve their scroll position so new items don't jump the viewport.
  4. A "Live" / "Paused" toggle button stops/resumes the interval.
  5. A "Jump to Latest" button appears when user has scrolled up. Clicking it scrolls to bottom.
  6. Clean up the interval in onWillUnmount.

Exercise 8 β€” Kanban Board (⭐⭐⭐ Intermediate)

Build: A multi-column Kanban board with drag-and-drop (or button-based move).

Concepts: Component composition, useState arrays (splice/push), sub-components, events, t-foreach in t-foreach

Acceptance criteria:

  1. Three columns: To Do, In Progress, Done. Each has its own cards array in state.
  2. Each card: title, description, priority badge (Low/Medium/High with colors).
  3. Cards split across two components: KanbanColumn and KanbanCard.
  4. "Move Right" / "Move Left" buttons on each card move it to adjacent column.
  5. Add card form at the bottom of each column. Validates non-empty title.
  6. Total card count displayed per column header. Overall count in the board header.

Advanced (Exercises 9–12)

Exercise 9 β€” Error Boundary Dashboard (⭐⭐⭐⭐ Advanced)

Build: A dashboard with multiple independent widgets, each wrapped in an error boundary.

Concepts: onError, error boundaries, t-key remount, async error handling, retry patterns

Acceptance criteria:

  1. Build a reusable ErrorBoundary with retry support (increments t-key to remount child).
  2. Four dashboard widgets: Sales Summary, Revenue Chart (simulated), User Stats, Activity Feed.
  3. Each widget has a 20% random chance of throwing an error in onWillStart (to simulate failures).
  4. Failed widgets show an error card with the error message, a "Retry" button, and a timestamp.
  5. Retry increments the t-key, forcing a fresh mount β€” the new instance re-runs onWillStart.
  6. Other widgets continue working when one fails β€” failures are isolated.

Exercise 10 β€” Async Search with Concurrency Control (⭐⭐⭐⭐ Advanced)

Build: A search component that demonstrates safe concurrent async state management.

Concepts: AbortController, race condition prevention, debouncing, onWillUnmount cleanup

Acceptance criteria:

  1. Input with 400ms debounce using a custom useDebounce hook.
  2. Each search call uses AbortController. Previous request is cancelled when a new one starts.
  3. Simulate network delay with random jitter (200–800ms) to make race conditions visible without the fix.
  4. Show a loading indicator only while the current request is in flight (not during debounce wait).
  5. Show cached results from the previous search while loading the new ones (stale-while-revalidate).
  6. Clean up any pending request and debounce timer in onWillUnmount.

Exercise 11 β€” Mini Odoo Field Widget (⭐⭐⭐⭐ Advanced)

Build: A complete Odoo field widget registered in the fields registry.

Concepts: @odoo-module, registry, standardFieldProps, orm, record.update, __manifest__

Acceptance criteria:

  1. Build a TagsWidget for many2many fields. Shows existing tags as removable chips.
  2. An autocomplete input searches available tags via orm.searchRead as the user types.
  3. Selecting a suggestion adds it to the field. Clicking βœ• on a chip removes it.
  4. Respects the readonly prop β€” no add/remove in readonly mode.
  5. Registered in registry.category("fields") for supportedTypes: ["many2many"].
  6. Add to a res.partner form view many2many field and test in Odoo.

Exercise 12 β€” Complete Odoo Client Action (⭐⭐⭐⭐⭐ Advanced)

Build: A full-featured Odoo client action: a KPI dashboard with live data from the ORM.

Concepts: Client action registration, orm, notification, action, user, dialog services, error boundaries, lifecycle

Acceptance criteria:

  1. Register as a client action (registry.category("actions")) and add an ir.actions.client record.
  2. Load KPI data in onWillStart via 3 separate orm.searchRead calls (sale orders, partners, invoices).
  3. Display metric cards: total revenue this month, new customers this month, overdue invoice count.
  4. A date range filter (This Week / This Month / This Year) that re-fetches data on change.
  5. A "Confirm All Drafts" button that calls orm.call with a ConfirmationDialog first.
  6. Wrap each metric section in an error boundary. Show a notification on successful bulk confirm.

πŸ“‹ Exercise Completion Checklist

  • Exercises 1–4: Core OWL (components, state, templates) β€” can complete after Core Concepts section
  • Exercises 5–6: Component design and hooks β€” complete after Advanced OWL section
  • Exercises 7–8: Lifecycle + composition β€” complete after Lifecycle section
  • Exercises 9–10: Error handling + concurrency β€” complete after Advanced OWL section
  • Exercises 11–12: Odoo integration β€” complete after Odoo Integration section