Every visible UI element must come from an Eddie component or recipe. Consumer projects contain zero custom component styles. No exceptions.
This means:
.my-card, .sidebar-item, .form-row)font-family, font-size, font-weight, or line-height<link> tags--ed-* CSS custom propertiesIf Eddie doesn't have a component you need, create a recipe — never write ad-hoc CSS in the consumer project.
Eddie is a themeable, framework-agnostic web component library built with Lit and TypeScript. It's published as four npm packages:
@brad-frost-web/eddie-web-components — 80+ Lit-based web components@brad-frost-web/eddie-design-tokens — Design tokens (CSS custom properties, SCSS, JSON)@brad-frost-web/eddie-icons — SVG icon sprite library@brad-frost-web/eddie-recipes — Product-specific compositions built on core componentsAll components use the <ed-*> tag prefix and work in any framework or plain HTML.
Available themes: bfw, bfw-dark, bfw-v9, wowee-zowee, we-are-here, altitude, southleft
The only CSS your app should contain:
That's it. Nothing else. Eddie handles everything.
If linking to the Eddie monorepo source (not published npm packages):
When building UI, use this table to find the right Eddie component. Never build these patterns from scratch.
| You need... | Use this | Example |
|---|---|---|
| Page shell | <ed-header> + <ed-main> |
Top-level page wrapper |
| Content width cap | <ed-layout-container> |
Wraps content inside header and main |
| Sidebar layout | <ed-layout variant="left-sidebar"> |
Two-column with sidebar |
| Layout columns | <ed-layout-section> |
Children of ed-layout |
| Content section | <ed-section> |
Has a header slot for section titles |
| Full-width band | <ed-band> |
Background-colored horizontal strip |
| Hero area | <ed-hero> |
Full-width hero with image support |
| You need... | Use this | Example |
|---|---|---|
| Top nav | <ed-primary-nav> + <ed-primary-nav-item> |
Main site navigation |
| Nav wrapper | <ed-nav-container> |
Contains primary nav in the header |
| Utility links | <ed-utility-nav> + <ed-utility-nav-item> |
Secondary nav (login, settings) |
| Link list | <ed-link-list> + <ed-link-list-item> |
Vertical list of links |
| Breadcrumbs | <ed-breadcrumbs> + <ed-breadcrumbs-item> |
Path breadcrumb trail |
| Pagination | <ed-pagination> + <ed-pagination-item> |
Page navigation |
| You need... | Use this | Example |
|---|---|---|
| Heading | <ed-heading tagName="h2"> |
Set tagName for semantic level, variant for visual size |
| Body text | <ed-text-passage> |
Wraps paragraphs, lists, blockquotes with proper typography |
| Link | <ed-text-link> |
Styled anchor |
| Divider | <ed-hr> |
Horizontal rule |
| Code block | <ed-code language="js"> |
Syntax-highlighted code |
| You need... | Use this | Example |
|---|---|---|
| Content grid | <ed-grid variant="3up"> + <ed-grid-item> |
Variants: 1-2up, 2up, 3up, 4up |
| Card | <ed-card> |
Content container with optional image |
| Data table | <ed-table> + header/body/row/cell children |
Structured data |
| Key-value pairs | <ed-key-value-table> + <ed-key-value-table-row> |
Label + value display |
| Badge | <ed-badge> |
Status indicator |
| Tag | <ed-tag> |
Label/category marker |
| Tag group | <ed-tag-list> |
Wraps multiple tags |
| Page title | <ed-page-header heading="Title"> |
With optional description and actions |
| Media + text | <ed-media-block> |
Image/icon alongside text |
| Feature block | <ed-feature> |
Highlighted feature display |
| You need... | Use this | Example |
|---|---|---|
| Text input | <ed-text-field label="Name"> |
Single-line text |
| Textarea | <ed-textarea-field label="Bio"> |
Multi-line text |
| Select | <ed-select-field label="Country"> |
Dropdown |
| Checkbox | <ed-checkbox-field> + <ed-checkbox-field-item> |
Multiple checkboxes |
| Radio buttons | <ed-radio-field> + <ed-radio-field-item> |
Single selection |
| Toggle switch | <ed-toggle label="Dark mode"> |
On/off toggle |
| File upload | <ed-file-upload> |
File picker |
| Search | <ed-search-form> |
Search input with submit |
| Range slider | <ed-range> |
Numeric range input |
| Field help text | <ed-field-note> |
Helper text for form fields |
| Button | <ed-button text="Submit" variant="primary"> |
Variants: primary, secondary, danger, ghost |
| Button group | <ed-button-group> |
Groups related buttons |
| You need... | Use this | Example |
|---|---|---|
| Alert banner | <ed-alert> |
Inline alert message |
| Toast message | <ed-toast> |
Temporary notification |
| Modal dialog | <ed-modal> |
Overlay dialog |
| Drawer panel | <ed-drawer> |
Slide-in panel |
| Tooltip | <ed-tooltip-trigger> + <ed-tooltip> |
Hover/focus tooltip |
| Loading spinner | <ed-loading-indicator> |
Loading state |
| Progress bar | <ed-progress> |
Progress indicator |
| Skeleton | <ed-skeleton> |
Loading placeholder |
| You need... | Use this | Example |
|---|---|---|
| Tabs | <ed-tabs> + <ed-tab> |
Tabbed content |
| Accordion | <ed-accordion> + <ed-accordion-panel> |
Expandable sections |
| Show/hide | <ed-show-hide> |
Toggle content visibility |
| Show more | <ed-show-more> |
Truncate with "show more" |
| You need... | Use this | Example |
|---|---|---|
| Icon | <ed-icon iconName="arrow-right"> |
SVG icon from sprite |
| Logo | <ed-logo> |
Brand logo |
| Box container | <ed-box> |
Generic styled container |
| Toolbar | <ed-toolbar> |
Actions bar |
| Counter | <ed-counter> |
Numeric count display |
| Dot | <ed-dot> |
Status dot indicator |
Recipes are product-specific compositions in @brad-frost-web/eddie-recipes. Use the <ed-r-*> tag prefix.
| Recipe | Tag | Description |
|---|---|---|
| Site Header | <ed-r-site-header> |
Full header with logo + nav + utility nav |
| Site Footer | <ed-r-site-footer> |
Full footer composition |
| Project Card | <ed-r-project-card> |
Card for project listings |
| Promo Block | <ed-r-promo-block> |
Promotional content block |
| Example Form | <ed-r-example-form> |
Form pattern reference |
Never use raw values. Always use Eddie CSS custom properties.
Use var(--ed-spacing-*) for all spacing: 2xs, xs, sm, md, lg, xl, 2xl, 3xl, 4xl, 5xl.
Use semantic color tokens, never raw hex/rgb values:
Eddie components handle their own typography. Use <ed-heading> for headings, <ed-text-passage> for body text. Never set font-family, font-size, or line-height directly.
If a UI pattern doesn't exist in Eddie core, create a recipe component — never write custom CSS in the consumer project.
npm run eddie-recipes:plop (from repo root)common/ for shared recipes, or a project-specific folder)packages/eddie-recipes/recipes/<project>/<recipe-name>/ed-r- (e.g., <ed-r-pricing-card>)ed-r-c- (e.g., .ed-r-c-pricing-card)EdElement (same base class as core components)When working with Eddie components, follow these naming patterns:
variant — Primary stylistic variation (e.g., "primary", "secondary", "danger")size — Abbreviated t-shirt sizes: xs, sm, md, lg, xltext — General string contenttitle — Heading contentlabel — Form field labelsiconName / iconPosition — Icon integrationimgSrc / imgAlt — Image propertiestagName — Override the HTML element rendered (e.g., tagName="h3")inverted — Boolean for dark-background color inversionhref — Makes component render as a linkThese are the most common mistakes. If an AI agent does any of these, it's wrong:
.my-sidebar, .step-indicator, .form-row, stop. Use an Eddie component or create a recipe.<link> tags. Import fonts.scss from the token package.var(--ed-spacing-*) for spacing, var(--ed-border-radius-*) for radii.<ed-heading>, <ed-text-passage>, and <ed-text-link>.<div> and <span> with custom styles — There's almost always an Eddie component for it.<ed-layout>, <ed-grid>, <ed-layout-container>.<button> + custom styles — Use <ed-button>.If you are an AI assistant building UI for a Brad Frost Web project:
--ed-* CSS custom property. Never hardcode values.eddie-recipes package.<div class="card">, stop — use <ed-card>.<html>.