SERVER-SIDE HTML COMPONENTS FOR CRYSTAL
COMPILED BEFORE RUNTIME
Can is a server-side HTML component system for
Crystal. Write componentized HTML in .can files,
compose it with defs, slots, and scoped CSS, then compile it into
Crystal before your app runs — no runtime template parser, no
client framework.
Can is pre-1.0 and aimed at experiments, small Crystal SSR projects, and developers who want componentized HTML without a browser-side runtime. A template writes HTML to an IO object, so the same components work with Kemal, Grip, plain HTTP::Server, or a small render script.
Components, isolated
Three cards, each defined by a different component. Every one of them
uses a .card class internally. They don't collide
because each component's CSS is rewritten to require a generated
attribute that only its own elements carry. Pop the source on any of
them — same class, no juggling.
Soft
source
<card-soft title="Soft">Pastel surfaces, rounded corners, a quiet voice.</card-soft>Bold
source
<card-bold title="Bold">High-contrast, monospace heading, a hard drop shadow.</card-bold>Paper
source
<card-paper title="Paper">Quiet serif, paper texture, a marginal note.</card-paper>One component, many variants
The same <callout> component renders three
different ways, picked by a kind param. Param-driven
style is just an expression attribute
(class={"callout #{kind}"}) plus a <.if>
chain inside the body.
crystal run.
Can.raw() or <.raw> only for content you've already sanitized.
source
<callout kind="info">Server-rendered. No client runtime, …</callout>
<callout kind="warning">Slot-bearing components must be defined …</callout>
<callout kind="danger">Use Can.raw() or <.raw> only for content …</callout>Made of canned templates
This particular page is one static HTML file produced by
crystal run docs/build.cr — every component
you see was defined in a .can file and compiled at
build time. The same components work unchanged inside a live HTTP
handler that writes to env.response; the build script
is just one way to consume the rendered output.