Contributing
Thank you for your interest in contributing to Lumeo. This guide walks through setting up the project, understanding the codebase structure, creating components, writing documentation, and running tests.
Getting started
Prerequisites
- .NET 10 SDK — Download from dotnet.microsoft.com.
- Node.js — Required for Tailwind CSS processing. Any recent LTS version works.
- IDE — Visual Studio 2022+, JetBrains Rider, or VS Code with the C# Dev Kit extension.
Clone and build
The docs site will be available at https://localhost:5001 (or the port shown in your console).
Build and pack
Project structure
The repository is organized into three main areas:
| Path | Description |
|---|---|
| src/Lumeo/ | The component library. Published as the Lumeo NuGet package. |
| src/Lumeo/UI/ | All components, organized by name. Each component lives in its own folder (e.g. UI/Button/, UI/Dialog/). |
| src/Lumeo/Services/ | Shared services: ToastService, OverlayService, ThemeService, KeyboardShortcutService, ComponentInteropService. |
| src/Lumeo/wwwroot/ | Static assets. CSS in css/, JavaScript in js/. |
| docs/Lumeo.Docs/ | The documentation site (Blazor Server). Contains pages, layouts, and shared components. |
| tests/Lumeo.Tests/ | Unit and integration tests using bUnit. |
Creating a component
Every component follows a consistent structure. Here is a step-by-step guide.
1. Create the component folder
Create a new folder under src/Lumeo/UI/ named after your component.
For example, src/Lumeo/UI/MyComponent/.
2. Follow the required conventions
Every .razor file must include these elements:
Key rules:
-
@namespace Lumeo must be the first line of every
.razorfile. -
Class parameter — Always include
[Parameter] public string? Class { get; set; }for consumer CSS overrides. -
AdditionalAttributes — Always include
[Parameter(CaptureUnmatchedValues = true)]and spread it on the root element with@attributes. -
CSS class combining — Use the pattern
$"{BaseClasses} {Class}".Trim()to merge base and consumer classes.
3. Use CSS variables for all colors
Never use hardcoded hex or HSL values. Always reference CSS variables through Tailwind utility classes:
| Do | Do not |
|---|---|
| bg-primary | bg-blue-500 |
| text-foreground | text-gray-900 |
| border-border | border-[#e5e7eb] |
| bg-muted | bg-[hsl(210,40%,96%)] |
Do not use Tailwind dark: prefixes.
Dark mode is handled entirely through CSS variable swaps in
lumeo.css.
4. Define enums inside the component
If your component needs variants, sizes, or other enumerated options, define the enum as a nested type inside the
@code block:
Consumers reference these as Alert.AlertVariant.Success.
5. Use CascadingValue for state
When child components need to read parent state, use CascadingValue with a context record.
Define the record as a nested type in the parent component. Use IsFixed="false" when the state can change.
6. JS interop through ComponentInteropService
Never inject IJSRuntime directly in components. Instead, inject
ComponentInteropService and call its methods:
7. Icons
Use the Blazicon component
from the Blazicons.Lucide package:
Adding documentation
Every component should have a corresponding documentation page in the docs site.
1. Create the page file
Add a new .razor file
under docs/Lumeo.Docs/Pages/Components/.
Use this template:
2. Required sections
- Header — Component name as an H1, followed by a brief description.
- Live demos — Interactive examples showing the component in action. Use bordered cards for each example.
- When to use — A list of appropriate use cases for the component.
- API reference — A table listing all parameters with their types, defaults, and descriptions.
3. Add to the navigation
Open docs/Lumeo.Docs/Layout/NavMenu.razor
and add a <NavLink> in the appropriate category section.
Running tests
The test suite uses bUnit for component testing.
Run all tests
Run a specific test
Test conventions
-
Place tests in
tests/Lumeo.Tests/, mirroring the source folder structure. -
Name test files
{ComponentName}Tests.cs. -
Use bUnit's
RenderComponent<T>to render and assert component output. - Test default rendering, parameter variations, event callbacks, and accessibility attributes.
Example test
Code style
Consistent code style keeps the codebase readable and maintainable. Here are the key conventions.
| Area | Convention |
|---|---|
| CSS framework | Tailwind CSS v4. All utility classes applied inline. |
| Colors | CSS variables only (bg-primary, text-foreground, etc.). No hardcoded hex/HSL values. |
| Dark mode | Handled by CSS variable swaps in lumeo.css. Never use dark: Tailwind prefixes. |
| Namespace | All component files use @namespace Lumeo. |
| Two-way binding | Property + PropertyChanged EventCallback pairs. |
| JS interop | Always through ComponentInteropService. Never inject IJSRuntime directly. |
| Enums | Defined as nested types inside the component's @code block. |
| Context records | Defined as nested public record inside the parent component. |
| Overlay cleanup | Implement IAsyncDisposable. Handle JSDisconnectedException in cleanup. |
| Icons | Use <Blazicon Svg="Lucide.X" /> from Blazicons.Lucide. |
Pull request guidelines
- One component per PR. Keep pull requests focused. If your change affects multiple components, split them into separate PRs.
- Include documentation. New components should come with a documentation page. Changes to existing components should update the relevant docs.
- Add tests. Include bUnit tests that cover the default rendering, parameter variations, and key interactions.
-
Build must pass. Run
dotnet build src/Lumeo/Lumeo.csprojanddotnet testbefore submitting. - Descriptive commit messages. Use clear, concise commit messages that describe the "why" behind the change.