Taxi.js Documentation

repository·main·Indexed 20 days ago

https://github.com/craftedbygc/taxi

A modern JavaScript page transition library providing AJAX-based navigation, routing, preloading, and script/CSS reloading. As the maintained successor to Highway.js, it enables smooth transitions between pages using a system of renderers and data attributes (data-taxi, data-taxi-view) to replace content without full page reloads.

Tokens
6.7K
Snippets
29
Records
34
Agent score
70%

What's inside @unseenco/taxi

  1. What is a Renderer and how to implement one

    main

    A Renderer is a class that runs every time a page is shown or hidden in Taxi. They are used for initializing or destroying components, playing intro animations, or managing page-specific logic.

    To create a Renderer, extend the @unseenco/taxi.Renderer class and implement the lifecycle methods. Within these methods, you have access to the following properties:

    • this.page: The entire document being rendered.
    • this.title: The document.title of the page.
    • this.wrapper: A reference to the data-taxi element.
    • this.content: A reference to the data-taxi-view element being added to the DOM.
    import { Renderer } from '@unseenco/taxi';
    
    export default class CustomRenderer extends Renderer {
      onEnter() {
        // run after the new content has been added to the Taxi container
      }
    
      onEnterCompleted() {
         // run after the transition.onEnter has fully completed
      }
    
      onLeave() {
        // run before the transition.onLeave method is called
      }
    
      onLeaveCompleted() {
        // run after the transition.onleave has fully completed
      }
    }
  2. How JS reloading works in Taxi

    main

    Taxi can reload and execute JavaScript found on a newly fetched page during the navigation cycle. This is useful for integrating with traditional CMSs (like WordPress or Magento) or for splitting heavy JavaScript into page-specific chunks.

    When enabled, Taxi parses and executes both external <script> tags and inline <script> blocks. This allows you to, for example, populate the window object with page-specific data via inline scripts.

    Lifecycle Timing: The reloading process occurs immediately after the NAVIGATE_IN event (once the new content is appended to the DOM) but before the Renderer.onEnter method is called.

  3. Understand route ordering and precedence

    main

    Taxi evaluates routes in the exact order they are declared. The first route that matches both the current and new URL regexes is the one that will be executed.

    Best Practice: Always declare specific routes (e.g., /pages/specific) before catch-all or wildcard routes (e.g., /pages/.*). If a catch-all route is declared first, it will intercept navigation intended for more specific routes, making the specific routes unreachable.

    // GOOD: Specific rules first, then catch-alls
    taxi.addRoute('/pages/specific', '', 'something')
    taxi.addRoute('/pages/.*', '', 'somethingElse')
    
    // BAD: The catch-all will prevent the specific rule from ever matching
    taxi.addRoute('/pages/.*', '', 'somethingElse')
    taxi.addRoute('/pages/specific', '', 'something')
  4. Handle navigation events

    main

    Taxi uses @unseenco/e for event handling. You can listen to lifecycle events during navigation using .on() and remove them using .off().

    Available Navigation Events

    • NAVIGATE_IN: Fired every time a data-taxi-view is added to the DOM.
    • NAVIGATE_OUT: Fired before the onLeave() method of a transition is run to hide a data-taxi-view.
    • NAVIGATE_END: Fired every time the done() method is called in the onEnter() method of a transition.

    Adding Listeners

    taxi.on('NAVIGATE_IN', ({ to, trigger }) => {
      // ...
    })

    Removing Listeners

    • To remove a specific callback: taxi.off(event_name, callback)
    • To remove all listeners for a specific event: taxi.off(event_name)
    import { Core } from '@unseenco/taxi'
    const taxi = new Core({ ... })
    
    function foo() { /* ... */ }
    
    // Add listener
    taxi.on('NAVIGATE_OUT', foo)
    
    // Remove just the foo listener
    taxi.off('NAVIGATE_OUT', foo)
    
    // Remove all listeners for this event
    taxi.off('NAVIGATE_IN')
  5. Understand the Taxi navigation lifecycle

    main

    When a user navigates to a new page, Taxi follows a specific sequence of events involving fetching content, selecting a transition, and executing lifecycle hooks on both the current and new Renderers.

    The Navigation Sequence:

    1. Fetch: Taxi fetches the new page and attaches it to the current Document (triggering asset downloads like images).
    2. Transition Selection: Taxi determines which Transition to use.
    3. Old Renderer Exit:
      • The current Renderer's onLeave method is called.
      • The chosen Transition's onLeave method is called (this is where old content is removed, unless removeOldContent: false was set during Taxi initialization).
      • The current Renderer's onLeaveCompleted method is called.
    4. New Content Injection: Taxi adds the new page's content to the container.
    5. New Renderer Entry:
      • Taxi identifies the new Renderer via the data-taxi-view attribute on the new page content (or uses the default).
      • The new Renderer's onEnter method is called.
      • The Transition's onEnter method is called.
    6. Completion: Once the transition finishes, the new Renderer's onEnterComplete method is called.
  6. Manage caching and prefetching in Taxi

    main

    Caching

    Taxi caches the contents of URLs after fetching them to speed up repeated visits.

    • To disable caching globally, set bypassCache: true in the Core constructor.
    • To force a specific page to always be fetched (bypassing cache), add the data-taxi-nocache attribute to the data-taxi-view element on that page.

    Prefetching

    By default, Taxi preloads links when a user triggers a mouseenter or focus event. To disable this behavior, set enablePrefetch: false in the Core constructor.

  7. How transitions are chosen during navigation

    main

    Taxi follows a specific hierarchy to determine which transition to execute when a user navigates:

    1. Explicit Transition: If a link has a data-transition attribute (e.g., <a data-transition="myTrans">), Taxi will use the registered transition matching that name. Note: Browser navigation (back/forward) will not trigger explicit transitions.
    2. Route Transition: If no explicit transition is found, Taxi checks the defined routes (via the router) to see if a contextual transition is matched for that specific route.
    3. Default Transition: If neither an explicit transition nor a route-specific transition is found, Taxi falls back to the registered default transition.
    <!-- Example of an Explicit Transition -->
    <a href="/some/page/" data-transition="someTransition"> ... </a>
  8. Customize which links trigger transitions

    main

    Taxi only transitions links that point to the same domain as the current URL. By default, it ignores links that:

    • Have a data-taxi-ignore attribute.
    • Are anchor links (e.g., #section) on the current page.
    • Have a target attribute.

    You can customize this behavior by providing a custom CSS selector to the links option in the Core constructor.

    const taxi = new Core({
        links: 'a:not([target]):not([href^=\#]):not([data-taxi-ignore])'
    })
  9. Use Taxi via CDN

    main

    You can include Taxi directly in your HTML using unpkg.com. Note that when using the UMD build via CDN, the main export is taxi (lowercase 't').

    <script src="https://unpkg.com/@unseenco/e@2.2.2/dist/e.umd.js" crossorigin></script>
    <script src="https://unpkg.com/@unseenco/taxi@1.0.3/dist/taxi.umd.js" crossorigin></script>
    
    <main data-taxi>
        <article data-taxi-view>
            ...
        </article>
    </main>
    
    <script>
        const t = new taxi.Core()
    </script>
  10. Associating a Renderer with a page

    main

    To trigger a specific renderer when a page is loaded, set the data-taxi-view attribute on the view element to match the key used during registration.

    If the data-taxi-view attribute is present but has no value (<div data-taxi-view>), Taxi will attempt to run the renderer registered under the key default.

    <!-- To use the 'someOther' renderer -->
    <div data-taxi-view="someOther">
        ...
    </div>
    
    <!-- To use the 'default' fallback renderer -->
    <div data-taxi-view> ... </div>
  11. Reload CSS on new pages

    main

    Taxi can automatically reload and run CSS present on a new page after navigation. This feature executes immediately after the NAVIGATE_IN event and after new content is appended to the DOM, but before the Renderer.onEnter method is called.

    By default, Taxi only reloads stylesheets that possess the data-taxi-reload attribute.

    <!-- reloaded -->
    <link rel="stylesheet" href="/foo.css" data-taxi-reload />
    
    <!-- this is not reloaded -->
    <link rel="stylesheet" href="/bar.css" />