[SOLVED] How do you extend Shoelace web component in Typescript using Lit


After extending <sl-button> component in Lit, I am not getting Typescript errors for the wrong attributes being passed. For example, in the code snippet below, when I call <sl-button> with the wrong attribute typescript shows errors, but if I call <my-button> with the wrong attribute typescript doesn’t show any error.

import SlButton from '@shoelace-style/shoelace/dist/components/button/button.js';
import {html} from 'lit';
import {customElement} from 'lit/decorators.js';

export default class MyButton extends SlButton {
  constructor() {

export const Demo = () =>
    <my-button size="not-exists">Click here!</my-button> // shows no error on "size"
    <sl-button size="not-exists">Click here!</sl-button> // shows error on "size"

declare global {
  interface HTMLElementTagNameMap {
    'my-button': MyButton;


This appears to be working as expected. I believe what you’re looking for isn’t a TypeScript error, as TS doesn’t care about HTML attributes, but code completion for your editor.

I suspect you’re using VS Code with the custom data provided by Shoelace. This is what tells VS Code about registered Shoelace elements, and if you open up dist/vscode.html-custom-data.json you’ll see each tag and a list of available attributes.

If you’re extending and re-tagging Shoelace elements, you’ll need to provide your own custom data to VS Code.

A couple notes:

First, when you import components/button/button.js, you’re still registering a Shoelace button. In fact, your code is registering both <sl-button> and <my-button> because registration happens on import.

Second, Shoelace components aren’t built to be renamed. Many rely on tag names for things to work, such as <sl-menu> which expects children to be <sl-menu-item> and <sl-tab-group> which expects <sl-tab> and <sl-tab-panel> children. Renaming them will break things in unexpected ways.

Answered By – claviska

Answer Checked By – Gilberto Lyons (BugsFixing Admin)

Leave a Reply

Your email address will not be published. Required fields are marked *