Getting started with LWR / LWC OSS
Install one npm package, point your project at it, and use <fandry-*> components. Your bundler ships only the ones you use.
Requirements
Link to section RequirementsNode.js 18 or newer
An LWR or LWC OSS project using
lwc8.x (lwcis a peer dependency, so Fandry uses your copy)npm, or pnpm / yarn if you prefer
1. Install
Link to section 1. InstallOne package brings every component and its single third-party dependency (@tanstack/table-core, used by fandry-table). There is nothing else to install.
npm install fandryui
2. Initialize
Link to section 2. InitializeThe CLI detects your project from lwr.config.json or lwc.config.json and registers the package as a module source. You can also make this edit by hand.
npx fandry init lwr.config.json (after)
{
"lwc": {
"modules": [
{ "dir": "$rootDir/src/modules" },
{ "npm": "fandryui" }
]
},
"routes": [ ... ]
}
lwc.config.json projects
Plain LWC OSS projects keep the same record at the top level:"modules": [ { "npm": "fandryui" } ].3. Use a component
Link to section 3. Use a componentThe package brings its own fandry namespace, so fandry/button is <fandry-button>. No imports are needed in your template.
<template>
<fandry-button onclick={handleSave}>Save</fandry-button>
<fandry-select
label="Fruit"
options={options}
value={fruit}
onchange={handleChange}
></fandry-select>
</template>
src/modules/my/app/app.js
import { LightningElement } from 'lwc';
export default class App extends LightningElement {
fruit = 'apple';
options = [
{ label: 'Apple', value: 'apple' },
{ label: 'Banana', value: 'banana' }
];
handleSave() {}
handleChange(event) {
this.fruit = event.detail;
}
}
What your project looks like
Link to section What your project looks like Directory structuremy-lwr-app/
├── lwr.config.json # { "npm": "fandryui" } added by `fandry init`
├── fandry.json # written by `fandry init`
├── package.json # "fandryui" in dependencies
├── node_modules/
│ └── fandryui/
│ ├── lwc.config.json # the public modules ("expose")
│ ├── registry.json
│ └── modules/fandry/ # readable source, one folder per component
│ ├── base/
│ ├── button/
│ ├── select/
│ └── table/ ...
└── src/
└── modules/
└── my/
└── app/ # your code
├── app.html
└── app.js
Everything under node_modules/fandryui is readable LWC source. Fandry is not a black box: open a component to see exactly what it does.
Only what you use ships
Link to section Only what you use shipsThere is no registry and nothing is registered globally. Your bundler follows the module graph from your templates, so a page that uses fandry-button does not include table, dialog or lookup. There is nothing to add with the CLI on this platform.
Next steps
Link to section Next stepsExtend the shared base class:
import Base from "fandry/base"gives your own component Fandry's stylesheet and design tokens.Theme by setting any
--fd-*token on:root(e.g.--fd-primary: 210 90% 40%; --fd-radius-md: 0), or on one section to theme just that part of the page.Restyle one element inside a component with
::part(), e.g.fandry-link::part(link). Each component page lists its parts.Need a change inside a component that neither CSS nor slots can reach? Copy it into your own namespace and make it yours. Its source is short, plain LWC; keep
extends Baseand it still follows your tokens.Browse every component, its props and examples under Components.
Build fails with LWC1121 in @lwrjs/loader?
Fresh installs oflwr 0.18.3 can pull @lwc/compiler 9.x, which rejects LWR's own loader. Pin your @lwc/* packages to the same 8.x version as lwc (npm "overrides"). The repository's examples/consumer/package.json shows a working set.Ready to build? Browse every component, its props and examples under Components.