Attribute Inheritance

Any attribute on a component usage tag that is not a Bascik-specific attribute (data-bascik-*) is automatically merged onto the component's root element. This is analogous to Vue's "fallthrough attributes".

How It Works

When Bascik transpiles a component, it reads the usage tag, extracts any inheritable attributes, and merges them onto the first element of the compiled output. The component template and the usage attributes are combined, classes are appended, all other attributes are forwarded:

html
<!-- usage in your page HTML -->
<site-nav
  class="sticky"
  aria-label="main navigation"
  data-testid="main-nav">
</site-nav>

<!-- site-nav.html - component template -->
<nav class="nav">
  <a href="/">Home</a>
</nav>
View compiled output
html
<!-- compiled output -->
<nav
  class="bascik__site-nav__nav sticky"
  aria-label="main navigation"
  data-testid="main-nav">
  <a href="/">Home</a>
</nav>

Class Merging

When the root element already has a scoped class, the inherited class is appended rather than replacing it.

html
<!-- root element has scoped class -->
<nav class="bascik__site-nav__nav">...</nav>

<!-- after merging class="sticky" -->
<nav class="bascik__site-nav__nav sticky">...</nav>

What Gets Inherited

All attributes on the usage tag are inherited exceptdata-bascik-* attributes, which are consumed by Bascik for slots, props, and build instructions.

Common use cases:

  • Layout classes:class="sticky", class="hidden"
  • Accessibility:aria-label, role, aria-hidden
  • Testing hooks:data-testid, data-cy
  • Custom data: any data-* attribute except data-bascik-*

What Happens with id

id is treated like any other inheritable attribute unless the component root already has its own id.

html
<!-- usage -->
<brand-logo id="footer-logo"></brand-logo>
View compiled output
html
<!-- template root has no id -->
<div class="bascik__brand-logo__logo-wrap">
  <img src="/img/logo.svg" alt="Brand logo" />
</div>
View compiled output
html
<!-- compiled output - id forwarded from usage tag -->
<div class="bascik__brand-logo__logo-wrap" id="footer-logo">
  <img src="/img/logo.svg" alt="Brand logo" />
</div>

If the template root already defines an id, Bascik keeps the template's root id and does not overwrite it with the usage-site id. That prevents root-level collisions while still letting you anchor page-level CSS or JavaScript to a component root that does not already declare one.

Practical rule: If page code needs to target a component root by id, put the id on the usage tag only when the component root does not already define one.

Interaction with Scoped Classes

Inherited class names are not scoped, they are treated as global classes. This is intentional: you are passing a page-level concern onto the component's root element.

html
<my-card class="featured">
  <p>Featured content</p>
</my-card>

The featured class is a global class that you define in your page-level stylesheet, separate from the component's scoped CSS.

Self-closing syntax works too: Attribute inheritance works with both paired and self-closing usage syntax: <my-icon class="large" aria-hidden="true" />

MDN reference. Bascik forwards standard HTML attributes instead of inventing a new API. Use MDN's HTML attribute reference as the primary guide for what each inherited attribute means.

Disabling It

Attribute inheritance is enabled by default. Set inheritAttributes: false in bascik.config.js when you want every component root to be controlled only by its own template:

js
export const bascikConfig = {
  inheritAttributes: false,
};

Interactive Demo

The demo below forwards a class, an accessibility label, and a testing hook onto the component root.

src/components/inherit-demo-card/
html
<inherit-demo-card
  class="featured-card"
  aria-label="Featured inheritance demo"
  data-testid="inherit-demo">
</inherit-demo-card>
html
<article class="inherit-card">
  <p class="inherit-card-kicker">Template root</p>
  <h3 class="inherit-card-title">Attribute inheritance</h3>
  <p class="inherit-card-body">Usage attributes merge onto this root element at build time.</p>
</article>
css
.inherit-card {
  width: min(100%, 34rem);
  background: var(--elevated);
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: 24px;
}

.inherit-card-kicker {
  margin: 0 0 10px;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
}

.inherit-card-title {
  margin: 0 0 10px;
  font-size: 1.05rem;
}

.inherit-card-body {
  margin: 0;
  color: var(--text-muted);
}
html
<article
  class="bascik__inherit-demo-card__inherit-card featured-card"
  aria-label="Featured inheritance demo"
  data-testid="inherit-demo">
  <p class="bascik__inherit-demo-card__inherit-card-kicker">Template root</p>
  <h3 class="bascik__inherit-demo-card__inherit-card-title">Attribute inheritance</h3>
  <p class="bascik__inherit-demo-card__inherit-card-body">Usage attributes merge onto this root element at build time.</p>
</article>