Index âș 2. Dynamic Pages
This tutorial kicks off the Kitten Count series of tutorials (tutorials 2-9) that take you through the basics of Kitten by building and evolving an interactive page to count kittens.
Topics covered
- Dynamic pages (.page.js files).
- File system-based routing.
- The
kitten.html
tagged template string. - Security and string sanitisation.
- The
<page>
tag.
You know whatâs better than one kitten? Many kittens!
If you were following along from the previous tutorial, rename your index.html file to index.page.js (and otherwise create a new file called index.page.js) and update its contents to match the following:
let count = 1
export default () => kitten.html`
<h1>Kitten count</h1>
<p>${'đ±ïž'.repeat(count++)}</p>
`
Now run kitten
, go to https://localhost, and refresh the page to see the number of kittens increase each time you do.
âš Ooh, magic! âš
How does it work?
A page in Kitten is written in plain old JavaScript (and hence the page.js extension).
Kitten uses file system routing. So, in this example, your /index.page.js file is mapped to the root route (/) of your site.
đĄ Since Kitten pages â and components, etc., as youâll see later â are just JavaScript files, you donât need any extra tooling to make things with Kitten. Your editor of choice will likely already know how to work with JavaScript (and HTML and CSS) files or can be easily configured to do so.
A route in Kitten is just an exported default function inside of a JavaScript module. Any HTML you return from your route is sent to the browser.
You write your HTML inside of
kitten.html
tagged template literals. These are just standard JavaScript template literals (template strings) that get passed through a special global function calledkitten.html
that performs Kitten-specific magic.đ Important security note: Part of that magic relates to the security of your apps. Kittenâs
kitten.html
tagged template literal sanitises any content you interpolate into your templates by default. This is important in avoiding cross-site-scripting (XSS) attacks. Kitten does the right thing by default when you usekitten.html
but if you forget and return a snippet of HTML in a plain JavaScript string, for example, you will not be protected.
The example above contains the minimum code required to achieve our goal. However, hereâs a more explicit version in case youâre not familiar with JavaScript arrow functions. In the version below, you can explicitly see everything thatâs happening.
let count = 1
export default function route ({ request, response }) {
return kitten.html`
<h1>Kitten count</h1>
<p>${'đ±ïž'.repeat(count++)}</p>
`
}
With the above version of the code, itâs clear that what youâre exporting from the .page.js file is a route and that it gets passed a parameter object containing the HTTP request and response objects (which we are not using in this example).
Note that routes in Kitten take a parameter object (notice they are surrounded by { ⊠}
) instead of positional parameters which you might be familiar with from more traditional frameworks like Polka, Express, etc. Parameter objects make it easier to read code and are also used elsewhere in Kitten (components and fragments, the onConnect()
handler, etc.)
Demystifying things
Take a look at the title of the tab when you run the example. Do you see that it reads âKitten countâ?
Thatâs odd, you didnât tell Kitten to set the title of the page but if you look at the source code of the page, youâll see that itâs set in the <head>
of your page as:
<title>Kitten count</title>
Howâd that happen?
Well, Kitten tries to do the right thing by default. So, if you donât set a title for your page, it tries to derive one for you by looking to see if there is a <h1>
tag on your page and using that if there is. It might not be perfect but itâs better than nothing if all youâre doing is coding up a quick example.
But what if you want to set your own title?
Enter, the page
tag.
The <page>
tag
Kitten has a special tag called <page>
that you can use to set commonly found elements in the heads of your pages (lang
, title
, charset
, icon
, and viewport
) as well as to include the libraries that Kitten has first-class support for (HTMX, HTMX idiomorph extension, HTMX WebSocket extension, Alpine.js, and Water.css).
To use it, you simply include the tag anywhere on a page (or fragment or component):
let count = 1
export default () => kitten.html`
<page title='Kitten count example'>
<h1>Kitten count</h1>
<p>${'đ±ïž'.repeat(count++)}</p>
`
đĄ You can also use the
<page>
tag to add classes to the body tag. e.g.,
<page bodyClass='someClass someOtherClass'>
If you run the example now, youâll see that the title you supplied is shown instead of the default one derived from the <h1>
element.
đĄ In addition to the
<html>
tagâslang
attribute, the regular<head>
settings, and supported libraries, you can also use thesyntax-highlighter
attribute to automatically use the default highlight.js light and dark mode themes (the WCAG AA accessible Measured light and dark themes) for code blocks rendered from<markdown>âŠ</markdown>
sections in your code. If you want to choose your own theme instead, you can override default themes by manually adding any of the roughly 500 highlight.js themes that exist to your project and specify the relative or absolute URL to them in thesyntax-highlighter-theme-light
andsyntax-highlighter-theme-dark
attributes.
đĄ Youâll see later that you can set anything you want in the head of your pages using the special
HEAD
slot (<content for='HEAD'>âŠ</content>
) but the<page>
tag should let you set the most common things you need when making Small Web sites and apps with Kitten.
As you can see, Kitten is very easy to get started with. But if youâre planning on creating an application that you see yourself supporting for a long time, you might be wondering about maintainability. Specifically, what if we want to make our code easier to write and debug by implementing type safety?
Kitten has you coveredâŠ
Next tutorial: Type Safety