Help

Getting started with Lily

Pick a framework, clone the headless repo or the example app, and start composing your own pages.

Install

Lily is published as separate Git repos per framework. The fastest way to try it is to clone the headless repo for your stack:

git clone https://github.com/LilyDesignSystem/lily-design-system-react-headless
cd lily-design-system-react-headless
pnpm install

The same pattern works for the other frameworks:

  • lily-design-system-html-headless — no install needed; copy .html files
  • lily-design-system-svelte-headlesspnpm install
  • lily-design-system-react-headlesspnpm install
  • lily-design-system-vue-headlesspnpm install
  • lily-design-system-nunjucks-headlesspnpm install
  • lily-design-system-blazor-headlessdotnet build (in progress)

Lily is being released bit-by-bit; npm/PyPI/NuGet packaging is on the roadmap. For now, treat the source as the source of truth and copy what you need.

Use a headless component

Headless components ship semantic HTML, ARIA, and props — but no CSS. Here's a Button in each framework:

HTML

<button class="button" type="button" aria-label="Save">
  Save
</button>

Svelte

<script>
  import Button from "lily-design-system-svelte-headless/components/Button/Button.svelte";
</script>

<Button onclick={save}>Save</Button>

React

import Button from "lily-design-system-react-headless/components/Button";

<Button onClick={save}>Save</Button>

Vue

<script setup>
  import Button from "lily-design-system-vue-headless/components/Button.vue";
</script>

<Button @click="save">Save</Button>

Nunjucks

{% from "components/button/macro.njk" import button %}

{{ button({ text: "Save", type: "button" }) }}

Use a styled example

The example apps include CSS, routes, and full demo pages. The fastest way to experiment is to start the SvelteKit, Next, Nuxt, or Eleventy example app and view the demo at /components.

git clone https://github.com/LilyDesignSystem/lily-design-system-svelte-sveltekit-examples
cd lily-design-system-svelte-sveltekit-examples
pnpm install
pnpm run dev

Then open http://localhost:5173 and browse /components.

Styling and design tokens

Each component renders with a single kebab-case class on its root element. For example, <Button> renders <button class="button">. Style it however you like:

.button {
  background: var(--my-primary);
  color: #fff;
  padding: 0.75rem 1.5rem;
  border-radius: 0.5rem;
}
.button:hover { background: var(--my-primary-hover); }

The default Lily color palette (used in the example apps) is:

  • Primary: #2563eb
  • Danger: #dc2626
  • Warning: #f59e0b
  • Success: #16a34a
  • Page background: #f9fafb
  • Card background: #ffffff

These are suggestions, not requirements. Replace them with your own brand palette and Lily comes along happily.

Accessibility

Components target WCAG 2.2 AAA. They follow these patterns:

  • Semantic HTML elements over generic <div>s.
  • <label for="id"> linking labels to inputs.
  • aria-labelledby / aria-describedby for cross-references.
  • aria-invalid + aria-errormessage for error states.
  • role="alert" and aria-live for dynamic content.
  • aria-pressed, aria-expanded, aria-current for state.
  • Roving tabindex for grids.

Focus indicators are intentionally consumer-supplied — Lily never paints a default focus ring that conflicts with your design.

Internationalization

Every label, placeholder, error message, and button text is a prop. There are no hardcoded strings. Drop in your translation framework of choice — Paraglide, i18next, vue-i18n, react-intl, .resx files, anything.

For dates, numbers, and currencies, the components accept pre-formatted strings: you format with Intl.DateTimeFormat / Intl.NumberFormat / your preferred library and pass the result.

Testing

Each framework subproject ships its own tests using its idiomatic stack:

  • HTML: WebDriverIO running real browsers.
  • Svelte: Vitest + @testing-library/svelte.
  • React: Vitest + @testing-library/react.
  • Vue: Vitest + @testing-library/vue.
  • Nunjucks: Vitest with a render helper.
  • Blazor: bUnit (planned).

Tests use Vitest's built-in matchers only — never jest-dom matchers. This keeps the test suites portable.

Contributing

Lily is brand-new and welcomes collaboration. The most useful contributions right now are:

  • New components (especially patterns from established design systems).
  • Better example styling — show off what's possible.
  • Translations of example app strings.
  • Bug reports with a minimal reproduction.
  • Accessibility audits with screen readers and assistive tech.

Open issues and PRs against the relevant repo at github.com/LilyDesignSystem.

FAQ

Why headless instead of styled?

Pre-styled components are convenient — until they don't match your brand. Headless components are slightly more work up front but give you total control over the visual design. The example apps show one way to style them; you can take that or replace it entirely.

Why so many components?

Lily aims to cover the patterns most apps need without forcing you to build them from scratch. The catalog draws from a dozen established design systems plus original work — see About.

Can I use Lily with Tailwind?

Yes. Each component exposes a single kebab-case root class plus a consumer-provided className / class. Layer Tailwind utilities on top however you like.

Can I use Lily with semantic CSS frameworks like DaisyUI?

Yes. The kebab-case class names on the root element work as semantic CSS hooks. Pair Lily with a semantic framework and you get pre-styled components that still respect ARIA and i18n.

Is there an npm package?

Not yet. The headless repos are intended to be cloned and used directly, or vendored into your project. npm/PyPI/NuGet publishing is on the roadmap.

Why multi-licensed?

Different projects have different license needs. BSD and MIT are permissive, Apache-2.0 has a patent grant, and the GPL options support copyleft. Choose whichever fits your situation.

How do I report a bug or request a feature?

Open an issue on the relevant GitHub repo, or email joel@joelparkerhenderson.com.