Lit Web Component Approach
The <neem-button> is a standards-based custom element built with
Lit 3. It uses Shadow DOM with CSS custom properties
adopted from the global token sheet, so themes and dark mode work automatically.
Primary Button
Maps to Kotlin PrimaryButton. Full-width, 64dp height.
Secondary Button
Maps to Kotlin SecondaryButton. 2dp outlined border.
With Icons
Leading and trailing icon support via leadingIcon / trailingIcon properties.
Disabled State
Kotlin: enabled = false → surface.disabledContainer.
Usage — HTML
Drop <neem-button> anywhere in your HTML after importing the module.
<!-- 1. Import the component once --> <script type="module" src="/src/neem-button.ts"></script> <!-- 2. Use it like native HTML --> <neem-button label="Confirm Payment" variant="primary" ></neem-button> <!-- Leading icon --> <neem-button label="Secure Transaction" variant="primary" leadingIcon="<svg>...</svg>" ></neem-button> <!-- Loading state --> <neem-button label="Saving..." variant="primary" loading></neem-button> <!-- Disabled state --> <neem-button label="Not Allowed" variant="secondary" disabled></neem-button>
Source — src/neem-button.ts (Lit)
The key excerpt showing how all values come from tokens, not hardcoded numbers.
@customElement('neem-button')
export class NeemButton extends LitElement {
@property() variant: 'primary' | 'secondary' = 'primary';
@property() label = '';
@property({ type: Boolean, reflect: true }) disabled = false;
@property({ type: Boolean, reflect: true }) loading = false;
static styles = css`
button {
height: var(--neem-spacing-extra-extra-large); /* 64px */
border-radius: var(--neem-shapes-large); /* 16px */
font-size: var(--neem-typography-label-large-size); /* 16px */
transition: all var(--neem-motion-duration-short) var(--neem-motion-easing-standard);
}
button.secondary {
border: var(--neem-border-width-bold) solid var(--neem-border-secondary); /* 2px */
}
button:disabled {
background: var(--neem-surface-disabled-container);
color: var(--neem-text-disabled);
}
\`;
render() {
return html\`
<button class=\${this.variant} ?disabled=\${this.disabled || this.loading}>
<div class="content \${this.loading ? 'hidden' : ''}">
<slot name="leading-icon"></slot>
<span>\${this.label}</span>
<slot name="trailing-icon"></slot>
</div>
<!-- DottedLoadingIndicator -->
<div class="dots">
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
</div>
</button>
\`;
}
}