How Component and componentId covers and exposes its structure - inside craftkit
Tags: craftkit, javascript, shadowdom, webdev
Published: 2020-10-28 14:48:46


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ntpf26ujlafbeswbku6o.jpg)

| Prop        | desc.       |
|:------------|:------------|
| this.view   | shadow host |
| this.shadow | shadow root |
| this.root   | component root based on `template` |

`this.view`, `this.shadow` and `this.root` are Craft.UI.View's basic property that is defined by Craft.Core.Component the top level class of all views.

`this.view` is the top level DOM element of your component, having unique componentId. This is the Shadow Host of your component.

`this.shadow` is Shadow Root of your component, attached to `this.view` (Shadow Host) by open mode.

`this.root` is the first child of your template, and it is appended to the `this.shadow` (Shadow Root).

Your template is under the Shadow Root. Therefore CSS class name and DOM ID never conflict across the craftkit application. This is the **first key technology of craftkit** to enable comfortable OOP by encapsulating Component definition. 

For example: 

```javascript 
class Vehicle extends Craft.UI.View {
	whoami(){
		return this.shadow.getElementById('text').innerHTML;
	}
	style(componentId){
		return `
			.root { color:red; }
		`;
	}
	template(componentId){
		return `
			<div id="root" class="root">
				<span id="text">I'm Vehicle</span>
			</div>
		`;
	}
}
class Bike extends Vehicle {
	style(componentId){
		return super.style(componentId) + `
			.root { color:blue; }
		`;
	}
	template(componentId){
		return `
			<div id="root" class="root">
				<span id="text">I'm Bike.</span>
			</div>
		`;
	}
}
class Car extends Vehicle {
	style(componentId){
		return super.style(componentId) + `
			.root { color:purple; }
		`;
	}
	template(componentId){
		return `
			<div id="root" class="root">
				<span id="text">I'm Car.</span>
			</div>
		`;
	}
}
``` 

Bike and Car both cascade `.root` CSS class from Vehicle, but both `root` class independently applied and never conflict. 

By the principle of Shadow DOM specification, you cannot access inside of your component DOM element via its ID from out side of your component. 

But your can access inside of your component's element via componentId from any where you want.

Instantiated component is registered to the `Craft.Core.ComponentStack` by its unique `componentId`. If you set `Craft.Core.Defaults.ALLOW_COMPONENT_SHORTCUT` to true at boot time, you can also use the `componentId` as global variable. This is the **second key technology of craftkit**. 

This feature is used to call instance method from rendered template. 

```javascript 
class DangerousTruck extends Car {
	ignite(){
		this.shadow.getElementById('text').innerHTML = "🚛🔥🔥🔥";
	}
	cooldown(){
		this.shadow.getElementById('text').innerHTML = "I'm COOL Truck 😄";
	}
	style(componentId){
		return super.style(componentId) + `
			.root { color:purple; }
		`;
	}
	template(componentId){
		return `
			<div id="root" class="root">
				<span id="text" onclick="${componentId}.ignite()">
					I'm dangerous Truck.
				</span>
			</div>
		`;
	}
}
``` 

When you click the text, it ignites the truck!

Of course, you can call ignite method from global by something like this: 

```javascript 
Object.keys(Craft.Core.ComponentStack.container)
.filter( id => id.match('Dangerous') )
.map( danger => window[danger].cooldown() )
``` 

※ Object.keys for Craft.Core.ComponentStack.container returns array of componentId. This is String. So it is accessing from window object.

## NOTE

Above examples are runnable on playground.

```javascript 
var bike_view = new Bike();
bike_view.loadView();
Craft.Core.Context.getRootViewController().appendSubView(bike_view);

var car_view = new Car();
car_view.loadView();
Craft.Core.Context.getRootViewController().appendSubView(car_view);

bike_view.shadow.getElementById('text').innerHTML; //-> I'm Bike
bike_view.whoami();                                //-> I'm Bike

car_view.root.style.color = 'purple' //-> make 'I'm Car.' purple

var truck_view = new DangerousTruck();
truck_view.loadView();
Craft.Core.Context.getRootViewController().appendSubView(truck_view);

truck_view.ignite(); //-> 🚛🔥🔥🔥
``` 

🛺 Try CraftKit Playground:
https://github.com/craftkit/craftkit-playground