Glaze Basecoat
This is a collection of Lustre components mapped from Basecoat UI.
Basecoat UI is a Tailwind CSS-based component library inspired by shadcn/ui that works with any web stack.
For a full list of components, take a look at https://hexdocs.pm/glaze_basecoat or https://basecoatui.com/components/
Latest supported version is Basecoat v0.3.11.
GitHub Pages Demo: https://daniellionel01.github.io/glaze/glaze_basecoat/
Getting Started
gleam add glaze_basecoat@1
import glaze/basecoat
import glaze/basecoat/icon
import glaze/basecoat/theme
import glaze/basecoat/theme_switcher
import lustre/element/html
html.head([], [
// (Optional) Register Tailwind (if not already coming from your build-tool)
html.script(
[attribute.src("https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4")],
"",
),
// Don't forget this, if you're using Tailwind through a CDN!
theme.tailwind_v4_bridge_style_tag(),
// Register Basecoat Components
basecoat.register(basecoat.version),
// Register your theme
theme.style_tag(theme.default_theme()),
// Register Lucide icons, required by some components
icon.register_cdn("latest"),
// (Optional) Init theme switcher
theme_switcher.init_script(),
])
Example
In a real project this might look like this:
import glaze/basecoat
import glaze/basecoat/button
import glaze/basecoat/card
import glaze/basecoat/theme
import lustre/element/html
pub fn layout() {
html.html([], [
html.head([], [
// ...
theme_switcher.init_script(),
icon.register_cdn("latest"),
html.script(
[attribute.src("https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4")],
"",
),
theme.tailwind_v4_bridge_style_tag(),
basecoat.register(basecoat.version),
theme.style_tag(theme.default_theme()),
]),
html.body([], [
card.card([], [
card.header([], [
card.title([], [html.text("Welcome")]),
card.description([], [html.text("Hello!")]),
]),
card.content([], [
button.button([], [html.text("Get Started")]),
]),
]),
]),
])
}
You can find the full documentation here: https://hexdocs.pm/glaze_basecoat.
Take a look at the dev module for a kitchen sink of all components and how you might use them!
Tailwind CSS
Basecoat UI ships Tailwind-based styles. You can either use the CDN for a fast setup, or integrate it into your own Tailwind build.
TL;DR
| Scenario | CSS | JS | Use these functions |
|---|---|---|---|
| Use Tailwind CDN | Tailwind CDN + Basecoat CDN | Basecoat JS via CDN | Tailwind <script ...@tailwindcss/browser@4>glaze_basecoat.register(version)theme.style_tag(...)theme.tailwind_v4_bridge_style_tag() |
| Build-time Tailwind (CLI/PostCSS/Vite) | Your Tailwind build output (with @import "basecoat-css") | Basecoat JS via CDN | glaze_basecoat.register_js(version) theme.style_tag(...) |
| Manage CSS/JS separately (still CDN) | Basecoat compiled CSS via CDN | Only specific JS components via CDN | glaze_basecoat.register_css(version)glaze_basecoat.register_component(version, "popover") |
Option 1: Full CDN
Use basecoat.register() to include Basecoat’s compiled CSS and all Basecoat JavaScript via CDN.
Option 2: Tailwind Play CDN
If you use Tailwind’s CDN (https://tailwindcss.com/docs/installation/play-cdn), you also need Basecoat’s Tailwind v4
@theme mapping so utilities like bg-accent exist.
If you have a build-time Tailwind setup, you do not need this bridge (it comes from @import "basecoat-css").
import glaze/basecoat
import glaze/basecoat/theme
import lustre/attribute.{attribute}
import lustre/element/html
html.head([], [
html.script(
[attribute.src("https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4")],
"",
),
basecoat.register(basecoat.version),
theme.style_tag(theme.default_theme()),
theme.tailwind_v4_bridge_style_tag(),
])
Option 3: Build-time Tailwind
If you have a build-time Tailwind setup (Tailwind CLI/PostCSS/Vite/etc) and you install Basecoat from npm, you can import Basecoat directly in your Tailwind entry CSS.
npm install basecoat-css
@import "tailwindcss";
@import "basecoat-css";
In this case you should not use basecoat.register(), since it also includes Basecoat’s CSS from the CDN.
Use basecoat.register_js() (or basecoat.register_component()) to only include the JavaScript and let your Tailwind build produce the CSS.
import glaze/basecoat
import glaze/basecoat/theme
import lustre/attribute.{attribute}
import lustre/element/html
html.head([], [
basecoat.register_js(basecoat.version),
theme.style_tag(theme.default_theme()),
])
Option 4: Split CSS and JS (CDN)
If you want to manage CSS and JavaScript separately (still via CDN), register the compiled CSS and only the JS components you use.
import glaze/basecoat
import glaze/basecoat/theme
import lustre/element/html
html.head([], [
basecoat.register_css(basecoat.version),
basecoat.register_component(basecoat.version, "popover"),
theme.style_tag(theme.default_theme()),
])
Theming
Basecoat uses shadcn/ui compatible CSS variables. You can customize the theme:
import glaze/basecoat/theme
let custom_theme =
theme.default_theme()
|> theme.set(theme.Primary, "oklch(0.205 0 0)")
|> theme.set(theme.Radius, "0.5rem")
Browse available themes at ui.shadcn.com/themes.
You can also use tools like https://tweakcn.com/editor/theme!
Icons
Basecoat uses Lucide icons.
The icon helpers in glaze/basecoat/icon render placeholders like <i class="lucide" data-lucide="plus">.
To turn those placeholders into SVGs you must also load the Lucide runtime.
Lucide docs (including the CDN snippet): https://lucide.dev/guide/packages/lucide
Option 1: Bundled
Install lucide (npm/pnpm/bun) and use icon.init().
Note: icon.init() injects a <script type="module"> that does import lucide from "lucide".
That means your app must have a JS setup that can resolve the bare module specifier (bundler, import map, etc).
import glaze/basecoat/icon
import lustre/element/html
// Initialize Lucide
html.head([], [
icon.init(),
])
// Use icons
icon.plus([])
icon.search([])
Option 2: CDN
If you are not bundling JavaScript, include Lucide icons via CDN.
import glaze/basecoat/icon
html.head([], [
// Use a pinned version in real projects.
icon.register_cdn("latest"),
])
// Use icons (same API)
icon.plus([])
icon.search([])
FAQs
Client vs Server?
This library constructs HTML elements the same way on a client or on a server, so it is compatible in both environments.
Development
There is a dev module that constructs a Demo with all available elements and writes it to a .html file:
gleam dev
open ../docs/glaze_basecoat/index.html