Back to Hologram

Pages

docs-pages.md

latest4.6 KB
Original Source

Pages

Pages are specialized components that serve as entry points for different routes in your Hologram application. Together with regular components, they form the fundamental building blocks of Hologram applications. They inherit all the capabilities of components, including templates, state management, actions, commands, and event handling. For detailed information about these shared features, see the Components documentation.

Key Differences from Regular Components

While pages are built on top of components, they have some unique characteristics:

  • They must define a route using the route/1 macro
  • They must specify a layout component using either layout/1 or layout/2 macro, which serves as the root of the component tree and wraps the page's content (see Layouts for more information)
  • They use URL parameters instead of props
  • They are always stateful
  • They are always initialized on the server-side using init/3, unlike regular components which can be initialized on either client or server
  • Their init/3 function receives URL parameters (params) instead of component props (props)

Server-Side Rendering (SSR)

Every page is fully rendered to HTML on the server on first load, then becomes interactive on the client. Because the browser (and any crawler) receives complete, server-rendered markup, Hologram pages are SEO-friendly and fast to first paint out of the box, with no extra configuration.

This is why a page's init/3 always runs on the server: it produces the state used to render the initial HTML. Once the page is mounted in the browser, client-side state takes over and subsequent interactions happen without full page reloads (see Navigation for how transitions between pages work).

Basic Example

Here's a simple page implementation:

defmodule MyApp.GreetingPage do
  use Hologram.Page

  route "/hello/:username"

  layout MyApp.MainLayout

  def init(params, component, _server) do
    put_state(component, :username, params.username)
  end

  def template do
    ~HOLO"""
    <div>Hello, {@username}!</div>
    """
  end
end

Chaining Actions in Initialization

You can chain actions that will be executed when the page is mounted on the client:

def init(_params, component, _server) do
  put_action(component, :load_user_data)
end

Optional Initialization

The init/3 function is optional. If you don't need to initialize state or perform any preparation, you can omit it entirely - Hologram provides a default implementation that simply returns the Component and Server structs unchanged.

Server-side middleware attached to the page runs before init/3, so you can authenticate, authorize, or enrich the request before the page renders.

Routing and Parameters

Pages must define their URL route using the route/1 macro.

Routes can be static:

route "/products"

or contain dynamic parameters:

route "/users/:username/posts/:post_id/comments"

For routes with parameters, use the param/2 macro to specify how string parameters should be converted:

param :username, :string
param :post_id, :integer

Supported parameter types:

  • :atom - converts to atom
  • :float - converts to float
  • :integer - converts to integer
  • :string - keeps the parameter as string

Route Resolution

Hologram's router uses a search tree rather than ordered routing (like Phoenix or Rails). Static segments are always prioritized over parameterized ones automatically - so /users will always match before /:username, regardless of the order pages are defined. This eliminates a whole class of route shadowing bugs that are common in ordered routers, where adding a route in the wrong position can silently break another.

The tradeoff is that you can't have two ambiguous parameterized routes at the same level (e.g. /:username and /:post_slug). In practice, this is a design smell in any framework - the fix is always to give them distinct prefixes, such as /users/:username and /posts/:post_slug.

Component ID

The page is always assigned a component ID (cid) of "page". This is important to remember when targeting actions or commands at the page.

Sponsored by

Main sponsor

Milestone sponsor

Previous

← Components

Next

Layouts →