Azalea Kit UI 101
Azalea Kit UI is Azalea Health’s design system for our products. It is a collection of reusable web components and utilities that enable our engineers to:
- Improve UI consistency and quality
- Build things faster
- Build multiple applications that all share the same UI components
- Incrementally adopt components as needed
- Share guidelines and standards through documentation
- Improve communication between teams and people
Installation
Azalea Kit UI is distributed as a collection of standard ES modules that all modern browsers can understand. You can install Azalea Kit UI via npm.
To install the latest version:
npm install git@bitbucket.org:azaleahealth/azalea-kit-ui.git
To pin to a specific version range, add the dependency directly to your package.json using
npm’s Bitbucket shorthand with a semver selector:
{
"dependencies": {
"@azaleahealth/azalea-kit-ui": "bitbucket:azaleahealth/azalea-kit-ui#semver:^1.9.0"
}
}
Then run npm install. The ^1.9.0 range follows standard semver rules — it will
resolve to the latest 1.x.x release that is >= 1.9.0. Replace the version
constraint with any valid semver range (e.g. ~1.11.0 for patch-only updates, or
1.11.1 to pin exactly).
For projects not using npm, a stand-alone build is available for download here.
Now it’s time to configure your framework or bundler. Configurations vary for each tool, but here are some examples to help you get started.
Once your framework or bundler is configured, you’ll be able to import Azalea Kit UI components and utilities.
import '@azaleahealth/azalea-kit-ui/themes/light.css';
import '@azaleahealth/azalea-kit-ui/themes/dark.tokens.css';
import '@azaleahealth/azalea-kit-ui/components/button/button.js';
import '@azaleahealth/azalea-kit-ui/components/icon/icon.js';
import '@azaleahealth/azalea-kit-ui/components/input/input.js';
import { setBasePath } from '@azaleahealth/azalea-kit-ui/utilities/base-path.js';
// Set the base path to the folder you copied Azalea Kit UI's assets to
setBasePath('/path/to/azalea-kit-ui/dist');
// <ahi-button>, <ahi-icon>, and <ahi-input> are ready to use!
Component modules include side effects for registration purposes. Because of this, importing directly from
@azaleahealth/azalea-kit-ui may result in a larger bundle size than necessary. For optimal
tree shaking, always cherry pick, i.e. import components and utilities from their respective files, as
shown above.
Shipping both themes
Every theme is published twice:
| File | Contents | Use it when |
|---|---|---|
themes/light.css, themes/dark.css |
The theme’s tokens plus the shared utility tail | You load exactly one theme |
themes/light.tokens.css, themes/dark.tokens.css |
The theme’s tokens only | You load a second theme alongside the first |
The tail — .ahi-toast-stack, the density modifiers, .ahi-visually-hidden, and
@layer ahi-utilities — is theme-independent and identical in every theme, so loading two
complete theme files ships it twice. Load one complete theme and the other’s tokens instead:
import '@azaleahealth/azalea-kit-ui/themes/light.css'; // complete
import '@azaleahealth/azalea-kit-ui/themes/dark.tokens.css'; // tokens only
This is not only about the ~10KB. Those tail rules are unscoped, so with two complete files whichever one
loads last wins them outright — invisible while the two copies are identical, a load-order bug the day they
are not. Order the tokens files however you like: light.css declares its tokens at
:where(:root) (specificity zero) and dark.css at .ahi-theme-dark, so
specificity decides, not order.
Both themes must be present for .ahi-invert to work — it flips an element to the opposite
theme, and with only one theme loaded there is nothing to flip to.
Import paths
Cherry-picked imports can omit the dist/ prefix —
@azaleahealth/azalea-kit-ui/components/button/button.js and
@azaleahealth/azalea-kit-ui/dist/components/button/button.js resolve to the same module. Prefer
the shorter form in new code: it doesn’t tie your imports to the package’s internal build layout. The
dist/-prefixed paths continue to work and are not deprecated, so there is no need to rewrite
existing imports.
Both spellings are available for every subpath — components/, utilities/,
themes/, translations/, and fhir/.
Avoiding auto-registering imports
By default, imports to components will auto-register themselves. This may not be ideal in all cases. To import just the component’s class without auto-registering it’s tag we can do the following:
- import AhiButton from '@azaleahealth/azalea-kit-ui/components/button/button.js';
+ import AhiButton from '@azaleahealth/azalea-kit-ui/components/button/button.component.js';
Notice how the import ends with .component.js. This is the current convention to convey the
import does not register itself.
Load only one copy of Azalea Kit UI per page
Custom element names are global to the page. Azalea Kit UI registers each component under its
ahi- tag in the browser’s one shared registry, so
only one version of Azalea Kit UI can be active on a page at a time. The first copy to
register a tag owns it; any later copy that tries to register the same tag is ignored.
This matters because the losing version doesn’t fail loudly — it simply doesn’t take effect. Every
<ahi-button> on the page is upgraded by whichever copy loaded first, even markup written
against a newer version. You’ll see a console warning for each affected tag:
Attempted to register <ahi-button> v2.0.0, but <ahi-button> v1.19.0 has already been registered.
If components behave like a different version than the one you installed — a missing property, an event that never fires, an attribute that seems to do nothing — check the console for this warning first.
Two copies usually get onto a page one of these ways:
-
Mixing distributions. Loading the CDN bundle (
azalea-kit-ui.js) on a page that also imports components from the npm package. Pick one per page. - An embedded widget or SDK that bundles its own copy. If you ship a library that depends on Azalea Kit UI and is embedded in an Azalea application, import the host page’s copy rather than bundling your own, so the host controls the version.
When you do vendor a copy of the built bundle, treat it and anything built against it as a matched set: upgrade them together, since a partial upgrade leaves two versions racing to register and load order decides which one wins.
Browser Support
We aim to support the latest versions of the following browsers. We do not support IE11 or pre-Chromium Edge.
Attribution
Special thanks to the following projects that help make Azalea Kit UI possible:
- Components are built with Lit
- Component metadata is generated by the Custom Elements Manifest Analyzer
- Documentation is powered by 11ty
- Icons are courtesy of Tabler Icons and Health Icons
- Positioning of dropdowns, tooltips, etc is handled by Floating UI
- Components and build process forked from Shoelace