# Glaze Basecoat
[](https://hex.pm/packages/glaze_basecoat)
[](https://hexdocs.pm/glaze_basecoat/)
This is a collection of Lustre components mapped from [Basecoat UI](https://basecoatui.com/).
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](https://github.com/hunvreus/basecoat).
GitHub Pages Demo: <https://daniellionel01.github.io/glaze/glaze_basecoat/>
## Getting Started
```sh
gleam add glaze_basecoat@1
```
```gleam
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:
```gleam
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](./dev/glaze_basecoat_dev.gleam) 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>`<br>`glaze_basecoat.register(version)`<br>`theme.style_tag(...)`<br>`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)` <br>`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)`<br>`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"`).
```gleam
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.
```sh
npm install basecoat-css
```
```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.
```gleam
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.
```gleam
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:
```gleam
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](https://ui.shadcn.com/themes).
You can also use tools like <https://tweakcn.com/editor/theme>!
## Icons
Basecoat uses [Lucide icons](https://lucide.dev).
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).
```gleam
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.
```gleam
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:
```sh
gleam dev
open ../docs/glaze_basecoat/index.html
```