Lion web components is a set of highly performant, accessible and flexible Web Components. They provide an unopinionated, white label layer that can be extended to your own layer of components.
For some more details see the announcement blog post.
We do have a live Storybook which shows all our components.
Please note: This project uses Yarn Workspaces. If you want to run all demos locally you need to get Yarn and install all depencies by executing yarn install
.
npm i @lion/<package-name>
The accessibility column indicates whether the functionality is accessible in its core. Aspects like styling and content determine actual accessibility in usage.
Package | Version | Description | Accessibility |
---|---|---|---|
-- Buttons -- | |||
button | Button | ✔️ | |
switch | Switch | ✔️ | |
-- Forms -- | |||
form | Wrapper for multiple form elements | ✔️ | |
field | Base Class for all inputs | ✔️ | |
fieldset | Group for form inputs | ✔️ | |
validate | Validation for form components | n/a | |
checkbox | Checkbox form element | ✔️ | |
checkbox-group | Group of checkboxes | ✔️ | |
input | Input element for strings | ✔️ | |
input-amount | Input element for amounts | ✔️ | |
input-date | Input element for dates | ✔️ | |
input-datepicker | Input element for dates with a datepicker | ✔️ | |
input-email | Input element for e-mails | ✔️ | |
input-iban | Input element for IBANs | ✔️ | |
input-range | Input element for a range of values | ✔️ | |
radio | Radio from element | ✔️ | |
radio-group | Group of radios | ✔️ | |
select | Simple native dropdown element | ✔️ | |
textarea | Multiline text input | ✔️ | |
-- Overlays -- | |||
overlays | Overlay System | ✔️ | |
dialog | Dialog element | ✔️ | |
tooltip | Tooltip element | #175 | |
-- Icons -- | |||
icon | Display our svg icons | #173, #172 | |
-- Navigation -- | |||
steps | Multi Step System | n/a | |
tabs | Move between a small number of equally important views | n/a | |
-- Others -- | |||
core | Core System (exports LitElement, lit-html) | n/a | |
calendar | Standalone calendar | #195, #194 | |
localize | Localize and translate your application/components | n/a | |
ajax | Fetching data via ajax request | n/a |
<script type="module">
import '@lion/input/lion-input.js';
</script>
<lion-input name="firstName"></lion-input>
<script type="module">
import { ajax } from '@lion/ajax';
ajax.get('data.json').then(response => {
// most likely you will use response.data
});
</script>
import { LionInput } from '@lion/input';
class MyInput extends LionInput {}
customElements.define('my-input', MyInput);
- High Performance - Focused on great performance in all relevant browsers with a minimal number of dependencies
- Accessibility - Aimed at compliance with the WCAG 2.0 AA standard to create components that are accessible for everybody
- Flexibility - Provides solutions through Web Components and JavaScript classes which can be used, adopted and extended to fit all needs
Lion Web Components aims to be future proof and use well-supported proven technology. The stack we have chosen should reflect this.
- lit-html and lit-element
- npm
- yarn
- open-wc
- Karma
- Mocha
- Chai
- ESLint
- prettier
- Storybook
- ES modules
- Lots and lots of tests
We know from experience that making high quality, accessible UI components is hard and time consuming: it takes many iterations, a lot of development time and a lot of testing to get a generic component that works in every context, supports many edge cases and is accessible in all relevant screen readers.
Lion aims to do the heavy lifting for you. This means you only have to apply your own Design System: by delivering styles, configuring components and adding a minimal set of custom logic on top.
Check out our coding guidelines for more detailed information.
Lion Web Components are only as good as its contributions. Read our contribution guide and feel free to enhance/improve Lion. We keep feature requests closed while we're not working on them.
The CustomElementRegistry provides methods for registering custom elements. One of the limitations of working with this global registry is that multiple versions of the same element cannot co-exist. This causes bottlenecks in software delivery that should be managed by the teams and complex build systems. Scoped Custom Element Registries is a proposal that will solve the problem. Since this functionality won't be available (especially not cross browser) anytime soon, we've adopted OpenWC's Scoped Elements.
Whenever a lion component uses composition (meaning it uses another lion component inside), we apply ScopedElementsMixin to make sure it uses the right version of this internal component.
import { ScopedElementsMixin, LitElement, html } from '@lion/core';
import { LionInput } from '@lion/input';
import { LionButton } from '@lion/button';
class MyElement extends ScopedElementsMixin(LitElement) {
static get scopedElements() {
return {
'lion-input': LionInput,
'lion-button': LionButton,
};
}
render() {
return html`
<lion-input label="Greeting" name="greeting" .modelValue=${'Hello world'}></lion-input>
<lion-button>Save</lion-button>
`;
}
}
Since Scoped Elements changes tagnames under the hood, a tagname querySelector should be written like this:
this.querySelector(getTagName('lion-input', this.constructor.scopedElements));
Avoid tagname css selectors (we already avoid query selectors internally in lion, but just be aware
that a selector like lion-input {...}
will stop working ).
Sometimes we need to render parts of a template to light dom for accessibility. For instance we render a node via lit-html that we append to the host element, so it gets slotted in the right position. In this case, we should also make sure that we also scope the rendered element.
We can do this as follows:
_myLightTemplate() {
return html`
This template may be overridden by a Subclasser.
Even I don't end up in shadow root, I need to be scoped to constructor.scopedElements as well.
<div>
<lion-button>True</lion-button>
<lion-input label="xyz"></lion-input>
</div>
`;
}
__getLightDomNode() {
const renderParent = document.createElement('div');
this.constructor.render(this._myLightTemplate(), renderParent, {
scopeName: this.localName,
eventContext: this,
});
// this node will be appended to the host
return renderParent.firstElementChild;
}
connectedCallback() {
super.connectedCallback();
this.appendChild(this.__getLightDomNode());
}
In a less complex case, we might just want to add a child node to the dom.
import { ScopedElementsMixin, LitElement, getScopedTagNamegetScopedTagName } from '@lion/core';
...
__getLightDomNode() {
return document.createElement(getScopedTagName('lion-input', this.constructor.scopedElements));
}
We encourage you to have a look at OpenWC's Scoped elements.
Feel free to create a github issue for any feedback or questions you might have. You can also find us on the Polymer slack in the #lion channel.
You can join the Polymer slack by visiting https://www.polymer-project.org/slack-invite.
As stated above "support and issues time" is currently rather limited: feel free to open a discussion. However, we can not guarantee any response times.