JavaScript-enabled Routing

Your routes, directly in JavaScript

Generate the URLs of your Symfony routes in JavaScript, exactly like path() and url() do in Twig.

composer require symfony/ux-router

What Router gives you

  • The same URLs

    Identical to what path() and url() return in Twig.

  • Only what you expose

    No route reaches JavaScript until you list it.

  • Typed parameters

    TypeScript checks route names and parameters.

  • Localized routes

    The current locale picks the right path.

  • Fresh in dev

    Change a route, the next request dumps it again.

Symfony Routes in JavaScript

Add Router to your app.

Generate your Symfony routes' URLs in JavaScript

src/Controller/UxPackage/RouterController.php
#[Route(
    '/router/demo/blog/{year}/{slug}',
    name: 'demo_blog_post',
    requirements: ['year' => '\d{4}'],
    options: ['expose' => true],
)]
public function blogPost(int $year, string $slug): Response
{
    // ...
}

#[Route(
    ['en' => '/router/demo/about', 'fr' => '/router/demo/a-propos'],
    name: 'demo_about',
    options: ['expose' => true],
)]
public function about(): Response
{
    // ...
}
assets/router.js
import { createRouter } from '@symfony/ux-router';
import { defaultLocale, routes } from '../var/routes/index.js';

/*
 * This file is part of the Symfony UX Router package.
 *
 * If folder "../var/routes" does not exist, or some routes are missing,
 * you must warmup your Symfony cache to refresh JavaScript routes.
 *
 * If you use TypeScript, you can rename this file to "router.ts" to take advantage of types checking.
 */

export const { path, url } = createRouter({ routes, defaultLocale });
Symfony logo

UX Router

path('demo_blog_post', {
    year: ,
    slug: ,
    _query: { page:  },
})
Path with a query string
url('demo_blog_post', {
    year: ,
    slug: ,
})
Absolute URL
path('demo_about', {
    _locale: ,
})
Localized route
path('demo_blog_post', {
    year: ,
    slug: ,
})
Requirement check

Dumped at cache warmup

How the routes get there.

Nothing is fetched at runtime. A cache warmer writes the routes you expose to disk, and your JavaScript imports them like any other module.

Exposed on purpose

Name patterns, or the expose option of a route, decide what JavaScript can see.

ux_router:
    routes:
        - 'app_*'
        - '!app_admin_*'

Written to disk

The exposed routes end up in one generated module, with TypeScript types next to it.

var/routes/
├── index.js
└── index.d.ts

The same path() and url()

Requirements, defaults, hosts, schemes and the query string behave the way they do in PHP.

import { path, url } from './router.js';

path('app_blog_show', { slug: 'hello', _query: { page: 2 } });
// '/blog/hello?page=2'

url('app_blog_show', { slug: 'hello' });
// 'https://example.com/blog/hello'

Install Router.

$ composer require symfony/ux-router

More from Symfony UX.

Router is one package among many. They share the same Stimulus foundation and install the same way.

Image for the Chart.js UX package

Chart.js

Easy charts with Chart.js

Image for the React UX package

React

Quickly render <React /> components & pass them props.

Image for the Vue.js UX package

Vue.js

Quickly render <Vue /> components & pass them props.

Browse every package

Keep Router at hand.

Documentation, the people behind it, and where to ask when something does not behave.