@titancasket/component-library
v0.10.7
Published
Titan Casket Vue 3 component library with design system - usable as Nuxt layer or standalone NPM package
Maintainers
Readme
Titan Casket Component Library
A Nuxt 4 + Vue 3 component library that powers Titan Casket customer journeys. The project ships typed UI primitives styled with Tailwind, documented scenarios, and a comprehensive quality bar enforced by automated testing.
Dual-purpose library:
- 📦 NPM Package: Install in any Vue 3 project
- 🔌 Nuxt Layer: Extend in Nuxt 4 applications
Installation
As NPM Package (Vue 3 Projects)
# Using npm
npm install @titancasket/component-library
# Using yarn
yarn add @titancasket/component-library
# Using pnpm
pnpm add @titancasket/component-librarySetup Tailwind CSS
Add the Titan preset to your tailwind.config.js:
export default {
presets: [require('@titancasket/component-library/tailwind.preset')],
content: ['./src/**/*.{vue,js,ts}', './node_modules/@titancasket/component-library/dist/**/*.{js,mjs}'],
};Import Components
<script setup>
import { TitanButton, TitanInput, TitanSelect, TitanIconSelect } from '@titancasket/component-library';
</script>
<template>
<TitanButton variant="default">Click me</TitanButton>
<TitanInput v-model="email" label="Email" type="email" />
</template>As Nuxt Layer (Nuxt 4 Projects)
Add to your nuxt.config.ts:
export default defineNuxtConfig({
extends: ['@titancasket/component-library'],
});Components and composables are auto-imported.
Available Components
UI Components
TitanButton
Button component with two variants and customizable sizes.
- Variants:
default(yellow fill),outline(transparent with yellow border) - Sizes:
sm,md,lg - Features: Optional arrow, disabled state, full accessibility support
<TitanButton variant="default" size="md" @click="handleClick">
Click me
</TitanButton>TitanIcon
Dynamic icon component that renders SVG icons from the auto-generated icon registry.
The library includes an automated icon system with 12 SVG icons:
- UI Icons (8): casket, casket-open, casket-closed, family, fire, question-mark, tombstone, urn
- Benefits Icons (4): cart, truck, casket, heart
Icons are automatically generated from public/icons/ and use currentColor for CSS-based styling.
<div class="w-6 h-6 text-titan-green-800">
<TitanIcon name="ui/casket" aria-label="Casket selection" />
</div>See TitanIcon documentation for details.
TitanInput
Floating label text input with validation support.
- Types:
text,email,password,number,tel,url - Features: Floating labels, error states, required field indicator, placeholder support
- Accessibility: Full ARIA support, keyboard navigation
<TitanInput
v-model="email"
label="Email Address"
type="email"
:required="true"
:error="hasError"
error-message="Please enter a valid email"
/>TitanTextarea
Multi-line text input with floating labels.
- Features: Auto-resizing, character limits, floating labels, error states
- Accessibility: ARIA support with proper labeling and error announcements
<TitanTextarea
v-model="message"
label="Your Message"
:rows="4"
:max-length="500"
:required="true"
/>TitanSelectContainer
Flexible select component with three visual variants:
- Inline: Pill-based buttons (compact, horizontal)
- Icon: Icon cards with custom icon slots
- Stacked: Full-width buttons with title and description
Features: Single/multi-select, custom values, keyboard navigation, ARIA support
<!-- Inline variant (pills) -->
<TitanSelectContainer
v-model="selected"
:options="['Option 1', 'Option 2', 'Option 3']"
variant="inline"
label="SELECT AN OPTION"
/>
<!-- Icon variant with slots -->
<TitanSelectContainer
v-model="disposition"
:options="[
{ value: 'buried', label: 'Buried' },
{ value: 'cremated', label: 'Cremated' }
]"
variant="icon"
label="CHOOSE A DISPOSITION"
>
<template #icon-buried>🪦</template>
<template #icon-cremated>⚱️</template>
</TitanSelectContainer>
<!-- Stacked variant with title/description -->
<TitanSelectContainer
v-model="serviceType"
:options="[
{
value: 'traditional',
label: 'traditional',
title: 'Traditional service',
description: 'A ceremony at a place of worship.'
}
]"
variant="stacked"
label="WITH A:"
/>
<!-- Multiple selection with custom values -->
<TitanSelectContainer
v-model="selected"
:options="['Flowers', 'Donation', 'Memorial']"
variant="inline"
multiple
allow-custom
show-checkmark
/>See TitanSelectContainer documentation for complete API and usage examples.
TitanSelect (Deprecated)
Pill-based single or multi-select component with custom value support.
- Note: This is now a wrapper around
TitanSelectContainerfor backward compatibility. New code should useTitanSelectContainerwithvariant="inline". - Modes: Single-select or multi-select
- Features: Keyboard navigation (Arrow keys, Home, End), custom value entry, disabled options, toggle deselect
- Styling: Selected items highlighted in Titan Purple, unselected in light green
<!-- Single select -->
<TitanSelect
v-model="selectedOption"
label="Choose one"
:options="['Option 1', 'Option 2', 'Option 3']"
/>
<!-- Multi-select with custom values -->
<TitanSelect
v-model="selectedItems"
label="Choose multiple"
:options="options"
:multiple="true"
:allow-custom="true"
/>TitanIconSelect (Deprecated)
Icon-based single-select component with card layout for visual selection.
- Note: This is now a wrapper around
TitanSelectContainerfor backward compatibility. New code should useTitanSelectContainerwithvariant="icon". - Layout: 100px × 102px cards with icons and labels
- Icons: Provided via named slots (e.g.,
#icon-buried) - Features: Single-select only, keyboard navigation (Arrow keys, Space, Enter), disabled state, required validation, optional checkmark
- Styling: Selected cards in Titan Purple with white text, unselected in light green with visible borders
- Accessibility: Full ARIA support with radiogroup/radio roles
<TitanIconSelect
v-model="selectedOption"
name="memorialization"
:options="[
{ value: 'buried', label: 'Buried' },
{ value: 'cremated', label: 'Cremated' },
{ value: 'other', label: 'Other' }
]"
:show-checkmark="false"
>
<template #icon-buried>
<svg><!-- Headstone icon --></svg>
</template>
<template #icon-cremated>
<svg><!-- Urn icon --></svg>
</template>
<template #icon-other>
<svg><!-- Flames icon --></svg>
</template>
</TitanIconSelect>TitanDatePicker
Date selection component with proper placeholder handling.
- Features: Date validation, required field support, error states, accessible labeling
- Accessibility: Proper ARIA attributes and keyboard support
<TitanDatePicker
v-model="selectedDate"
label="Select a date"
:required="true"
/>TitanImageUpload
Drag-and-drop image upload with preview.
- Features: Click or drag to upload, image preview, file validation, error handling
- Accessibility: Keyboard accessible with proper ARIA labels
<TitanImageUpload
v-model="uploadedImage"
label="Upload Image"
:max-size="5242880"
/>TitanInfoPanel
Informational panel component for displaying tips and guidance.
- Variants:
default(light background),compact(minimal padding),transparent(no background) - Features: Optional title, bullet list support, slot support for custom content
<TitanInfoPanel
title="Tips for a great photo"
:items="['Use high resolution', 'Ensure good lighting', 'Face the camera']"
variant="default"
/>TitanSubheader
Section heading component for organizing form content.
- Typography: 13px Work Sans Bold with uppercase styling (Figma-accurate)
- Features: Consistent spacing, Titan green color, custom class support
- Use Cases: Form section headers, content dividers, subsection titles
<TitanSubheader text="What are you envisioning for the parade elements?" />TitanProgressBar
Progress indicator with step counter for multi-step processes.
- Layout: Full-width bar with label showing current/total (e.g., "3/8")
- Design: 6px height bar with Titan yellow fill, 8px gap between bar and label
- Features: Smooth 500ms transitions, automatic percentage calculation, validation warnings
- Accessibility: Full ARIA progressbar support with value announcements
- Use Cases: Multi-step forms, onboarding flows, task completion tracking
<TitanProgressBar :current="3" :total="8" />Layout Components
TitanFormSection
Schema-based dynamic form renderer for creating forms declaratively.
- Features: Dynamic component rendering, v-model integration, mixed component support (form + non-form)
- Benefits: Reduced boilerplate, consistent spacing, easy form structure changes
- Schema Support: TitanInput, TitanTextarea, TitanSelect, TitanDatePicker, TitanSubheader, and more
<script setup>
const formData = ref({
paradeElements: '',
colors: '',
});
const schema = [
{
component: 'TitanSubheader',
props: { text: 'What are you envisioning for the parade elements?' }
},
{
component: 'TitanTextarea',
props: { label: 'Notes', rows: 3 },
model: 'paradeElements'
},
{
component: 'TitanSubheader',
props: { text: 'Any particular colors you would like represented?' }
},
{
component: 'TitanTextarea',
props: { label: 'Notes', rows: 3 },
model: 'colors'
}
];
</script>
<template>
<TitanFormSection v-model="formData" :schema="schema" />
</template>Composable: The useFormSchema() composable provides utilities for schema validation, form data initialization, and field validation.
TitanCard
Flexible card container with header, content, and optional logo.
- Variants:
default(white background),system(translucent with backdrop blur) - Features: Optional title, header slot, logo display (top-right), responsive design
- Styling: Rounded corners, shadow, grid-based layout
<TitanCard variant="default" title="Welcome" :logo="true">
<p>Your content goes here</p>
</TitanCard>TitanStepper
Step indicator component for multi-step forms and wizards.
- Features: Current step tracking, completed step indicators, step labels
- Accessibility: Proper ARIA landmarks and step announcements
<TitanStepper
:steps="['Personal Info', 'Upload Photo', 'Review']"
:current-step="1"
/>Design System
The library includes a complete Titan Casket design system with scientifically-generated color scales:
- Primary Green:
#003822(titan-green-800) - Main brand color - Secondary Yellow:
#facf60(titan-yellow-400) - Accent and CTAs - Tertiary Purple:
#3F1038(titan-purple-500) - Selection highlights
All components use these brand colors and are fully typed with TypeScript. Import the Tailwind preset to access the complete design token system.
Development Setup
- Install dependencies (Node 18+, Yarn 1.x):
yarn install - Launch the playground at
http://localhost:3000:yarn dev - Build the library for NPM publishing:
yarn build # Builds standalone Vue 3 library to dist/ - Build Nuxt layer or preview:
yarn build:nuxt # Build Nuxt layer yarn preview # Preview production build yarn generate # Generate static site
Scripts & Tooling
| Command | Purpose |
| ------------------------- | ---------------------------------------------------------------------------------- |
| yarn dev | Run the Nuxt development server with HMR. |
| yarn build | Build standalone Vue 3 library to dist/ (for NPM publishing). |
| yarn lib:build | Same as yarn build - builds NPM package. |
| yarn build:nuxt | Build Nuxt layer for production. |
| yarn preview | Preview the production build locally. |
| yarn generate | Produce static output for Jamstack-style hosting. |
| yarn prepare | Prepare Nuxt layer (runs automatically after install in Nuxt projects). |
| yarn storybook | Launch Storybook at http://localhost:6006 for interactive component development. |
| yarn build-storybook | Build Storybook as a static site for deployment. |
| yarn test | Execute Vitest unit suites with Happy DOM. |
| yarn test:watch | Keep Vitest running for rapid feedback. |
| yarn test:coverage | Generate coverage reports (minimum 80%). |
| yarn test:visual | Run Playwright snapshot tests across browsers. |
| yarn test:visual:update | Update Playwright baselines after approved design changes. |
| yarn test:storybook | Run Storybook test runner (Playwright-based) for story validation. |
| yarn test:all | Chain unit + visual + Storybook runs; required before PRs. |
Directory Layout
app/
├─ components/
│ ├─ ui/ # Exported UI primitives (TitanButton, TitanInput, TitanSelect, TitanIconSelect, ...)
│ │ # Each component has a .stories.ts file for Storybook
│ └─ layout/ # Structural/layout wrappers
├─ composables/ # Shared logic (useFormField, etc.)
├─ pages/ # Playground demos used by visual tests
├─ types/ # Component-specific TypeScript contracts
├─ utils/ # Reusable helpers and formatters
.storybook/
├─ main.ts # Storybook + Vite + Tailwind configuration
├─ preview.ts # Global styles and preview settings
└─ test-runner.ts # Playwright-based test runner config
docs/
├─ components/ # Consumer-facing component documentation
└─ templates/ # Documentation boilerplate for component docs
.agent/
└─ sop/ # Standard Operating Procedures (internal docs)
├─ component-creation-process.md
├─ testing-guide.md
└─ npm-publishing.md
tests/
├─ unit/ # Vitest specs grouped by domain
├─ visual/ # Playwright visual regression suites
├─ fixtures/ # Shared datasets and mocks
└─ templates/ # Copyable test scaffoldingNuxt, Tailwind, Vitest, and Playwright configurations live at the repo root (nuxt.config.ts, tailwind.config.js, vitest.config.ts, playwright.config.ts).
Component Development Workflow
Follow the repeatable process captured in .agent/sop/component-creation-process.md. In short:
- Plan props, events, and accessibility before coding.
- Scaffold Vue SFCs with
<script setup lang="ts">and two-space indentation. - Use Tailwind tokens from
tailwind.config.jsrather than custom values. - Create Storybook stories (
.stories.ts) alongside each component for interactive development and documentation. - Keep documentation, preview examples, and data-testids in sync with implementation.
Storybook Integration
Every UI component must have a corresponding .stories.ts file that:
- Documents all component variants and states
- Provides interactive controls for props
- Includes comprehensive examples (default, error, disabled, etc.)
- Serves as living documentation with auto-generated props tables
Run yarn storybook during development to iterate on components with instant feedback.
Testing Standards
- Unit tests live in
tests/unit/and rely on Vitest + @vue/test-utils; name filesComponentName.test.ts. - Visual snapshots live in
tests/visual/; cover every interactive state and rebaseline only after reviewing diffs. - Maintain ≥80% coverage by running
yarn test:coverage; HTML reports are emitted tocoverage/index.html. - End each iteration with
yarn test:allso regressions surface early.
For deeper guidance, reference .agent/sop/testing-guide.md.
Contributing
Before opening a pull request:
- Review the contributor playbook in
AGENTS.md(Repository Guidelines). - Use Conventional Commit prefixes (
fix:,docs:,chore:) with imperative subjects ≤72 characters. - Fill PR descriptions with motivation, linked issues, screenshots for UI changes, and test evidence.
