Comet
The picomet.backends.picomet.PicometTemplates
class implements Picomet’s template backend API for Django.
Layout
A Layout
is used by a page
<!-- comets/Base.html -->
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
<div s-group="page">
<Outlet />
</div>
</body>
</html>
<!-- apps/core/comets/pages/About.html -->
<Layout @="Base">
<div>
<Helmet>
<title>About</title>
</Helmet>
<h1>This is the about page</h1>
</div>
</Layout>
Warning
The Layout
tag must have one and only single html tag children.
Variable
To embed any data into a template, use the {$ $}
syntax or s-text
attribute.
<span>{$ request.method $}</span>
or
<span s-text="request.method"></span>
Expression in s-text
and {$ $}
is evaluated using the python’s built in eval
function.
DTL
If the comet syntax is not enough for you, Picomet provides Django Template Language
’s two features in comet template.
Variable
You can use DTL
’s double curly braces syntax if you want to use any filter.
<div>
{{ request.method|lower }}
</div>
Tag
You can use single DTL
tags inside comet templates.
<div>
{% url 'core:index' %}
</div>
Warning
Comet template doesn’t support multi tags like {% comment %}{% endcomment %}
Targets
Targets
is a list of strings, sent as a request header which picomet uses to partially render a page.
s-group
Picomet uses the s-group
attribute to partially render parts of a page on the server.
See how to use s-group
in the Action guide.
s-param
When you navigate from /&bookmarksPage=1
to /&bookmarksPage=2
, Picomet partially renders s-param="bookmarksPage"
elements in that page.
Form
For submitting forms, Picomet provides a custom Alpine.js directive named x-form
When the form is submitted, only the form element is partially rendered on the server.
<!-- apps/core/comets/Login.html -->
<form method="post" x-form>
<input type="text" name="username" s-bind:value="form['username'].value() or ''" />
<input type="password" name="password" s-bind:value="form['password'].value() or ''" />
<button type="submit">Login</button>
</form>
# apps/core/views.py
from django.contrib.auth import authenticate, login
from django.contrib.auth.forms import AuthenticationForm
from django.http import HttpRequest
from picomet.decorators import template
from picomet.views import render
@template("Login")
def login(request: HttpRequest):
context = {}
form = AuthenticationForm(request.user)
if request.method == "POST" and not request.action:
form = AuthenticationForm(request.POST)
if form.is_valid():
username = form.cleaned_data.get("username")
password = form.cleaned_data.get("password")
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
context["form"] = form
return render(request, context)
Head
Put content inside the head
tag from outside.
Helmet
Put title
and meta
tags inside the head
tag
<!-- apps/core/comets/Home.html -->
<Layout @="Base">
<div>
<Helmet>
<title>Home</title>
<meta name="title" content="..." />
<meta name="description" content="..." />
</Helmet>
<div>
</Layout>
Warning
Tags supported inside the Helmet
tag are title
and meta
.
Group
Define a place for a group of Css or Scss files
<head>
...
<Group name="styles" />
...
</head>
Assets
Css
/* apps/core/comets/Page.css or apps/core/assets/Page.css */
div a {
color: red;
}
Load it in a Group
<!-- apps/core/comets/Page.html -->
<Css @="Page.css" group="styles" />
<div>
<a>Link</a>
</div>
Sass
// apps/core/comets/Page.scss or apps/core/assets/Page.scss
div {
a {
color: red;
}
}
Load it in a Group
<!-- apps/core/comets/Page.html -->
<Sass @="Page.scss" group="styles" />
<div>
<a>Link</a>
</div>
Important
Sass
requires sass and javascript. Run npm i sass
and pip install javascript
Js
/* apps/core/comets/Page.js or apps/core/assets/Page.js */
export say(value){
alert(value);
}
<!-- apps/core/comets/Page.html -->
<Js @="Page.js" />
<button @click="say('hello')">say hello</button>
Ts
// apps/core/comets/Page.ts or apps/core/assets/Page.ts
export say(value: string){
alert(value);
}
<!-- apps/core/comets/Page.html -->
<Ts @="Page.ts" />
<button @click="say('hello')">say hello</button>
Important
Ts
requires esbuild and javascript. Run npm i esbuild
and pip install javascript
s-asset:
Import any asset from app/assets
or ASSETFILES_DIRS
<img s-asset:src="images/icon.png" />
Attribute
s-bind:
<a s-bind:href="blog.slug">{$ blog.title $}</a>
s-toggle:
Toggle boolean attribute
<button s-toggle:disabled="not user.is_authenticated"></button>
s-static:
Import any static file from app/static
or STATICFILES_DIRS
<link rel="stylesheet" s-static:href="styles/main.css" />
Component
Defining a component
<!-- apps/core/comets/Counter.html -->
<div x-data={count: 0}>
<button @click="count++">+</button>
<span x-text="count"></span>
<button @click="count--">-</button>
</div>
Using the component
<Include @="Counter" />
or
<Import.Counter @="Counter" />
<Counter />
Children
Defining a component with children
<!-- apps/core/comets/Card.html -->
<div class="card">
<Children />
</div>
Using the component
<Include @="Card">
card body
</Include>
or
<Import.Card @="Card" />
<Card>
card body
</Card>
Default
Setting default context props in a component
<!-- apps/core/comets/ProductItem.html -->
<Default show_add="True">
<div s-if="show_add">
add to cart
</div>
</Default>
Using the component
<Include @="ProductItem" /> <!-- show_add is True -->
or
<Include @="ProductItem" .show_add="False" /> <!-- show_add is False -->
Note
Use dot(.) prefix to provide a context variable to a component.
s-props
Pass normal attributes to a component
<!-- apps/core/comets/Component.html -->
<button s-props>click</button>
<Include @="Component" class="text-red-500" />
Condition
<div s-if="user.is_superuser">
hi admin
</div>
<div s-elif="user.is_authenticated">
hi user
</div>
<div s-else>
please login
</div>
<div s-show="user.is_superuser" s-group="auth">
hi admin
</div>
Warning
Use s-show
instead of s-if
with s-group
. Learn more about s-group
in the Action guide.
Loop
<div s-for="blog" s-in="blogs">
<div>
{$ blog.title $}
</div>
</div>
<div s-empty>
No blogs found
</div>
With
Pass a variable to a part of template
<With username="user.username">
{$ username $}
</With>
Debug
Contents inside the Debug
tag will only be parsed when Debug=True
in settings
.
<Debug>
<Js @="picomet/hmr.js" />
</Debug>
Tailwind
<!-- comets/Base.html -->
<!doctype html>
<html lang="en">
<head>
...
<Tailwind @="base" />
...
</head>
<body>
...
</body>
</html>
Warning
The Tailwind
tag must be inside the head tag.
Important
Tailwind
requires tailwindcss and javascript. Run npm i tailwindcss
and pip install javascript
For tailwind to work, picomet requires 3 files.
/* comets/base.tailwind.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
/** comets/base.tailwind.js */
/** @type {import('tailwindcss').Config} */
module.exports = {
theme: {},
plugins: [],
};
/** comets/base.postcss.js */
const tailwindcss = require("tailwindcss");
module.exports = {
plugins: [tailwindcss],
};
Alpine SSR
The cool thing about picomet is it’s ability to render alpine.js on the server
Note
Alpine.js directives supported on the server are x-data
, x-show
, x-text
, x-bind
. Learn more about these on alpinejs.dev
Important
To render Alpine.js syntax on the server Picomet requires py-mini-racer. Run pip install py-mini-racer
s-prop
To pass any data from the server context dictionary to the javascript context, use the s-prop directive.
# apps/core/views.py
from picomet.decorators import template
from picomet.views import render
@template("Page")
def page(request):
context = {"variable": "hello world"}
return render(request, context)
<!-- apps/core/comets/Page.html -->
<div s-prop:_var="variable" x-data="{var: _var}" server>
<span x-text="var"></span>
</div>
Important
The server
attribute is required to know if the alpine directives inside a block should be rendered on the server. The client
attribute can be used inside a server
block to exclude a block from being rendered on the server.