# Creating components

## Where to put it?

In this document, we consider the src directory of the project as the root.<br>
We describe how we organize our components as an example, however it depends on your project.

In concorde each component is currently organized in the following directory structure (at least we try):

- **/core/components/functional/component-name/component-name.ts**  
  Generic/functional/generally unstyled component.
  The component usually doesn't use any other concrete components.
- **/core/components/ui/component-name/component-name.ts**  
  Generic but UI-oriented component.
  The component usually only uses generic components and other UI components.
- **la-billetterie/components/atoms/component-name/component-name.ts**  
  The component is intended to have a concrete usage within our ticketing system **"la-billetterie"**.
  It usually only uses generic components from `core` and possibly other atoms.
- **la-billetterie/components/concrete-destination/component-name/component-name.ts**  
  The component has a specific destination: (event / cart / gift card): `/components/destination/`
  The component uses various components, usually from the `/components/atoms` directory.
  It does not use components at the same level in the file hierarchy.

## Starting from a Simple Model

You can copy `example.ts` from the source to the desired destination to start with.
This file contains a web component in the form of a class that extends the `Subscriber` mixin, with a reactive property and a render function.

<sonic-code language="javascript">
  <template>
import { html, LitElement } from "lit";
import { customElement, property } from "lit/decorators.js";
import Subscriber from "@supersoniks/concorde/core/mixins/Subscriber";

@customElement("sonic-example")
export class SonicComponent extends Subscriber(LitElement) {
  @property() text = "Example";
  render() {
    return html`${this.text}`;
  }
}
  </template>
</sonic-code>

**You can remove the dependency on `Subscriber`** if automatic population of the component with external data is not required.
For example, for a UI component:


<sonic-code language="javascript">
  <template>
import { html, LitElement } from "lit";
import { customElement, property } from "lit/decorators.js";

@customElement("sonic-example")
export class SonicComponent extends LitElement {
  @property() text = "Example";
  render() {
    return html`${this.text}`;
  }
}
  </template>
</sonic-code>

Regarding `Subscriber`, see:

- [🔔 Subscriber](#docs/_core-concept/subscriber.md/subscriber)
- [🥨 Sharing Data](#docs/_getting-started/pubsub.md/pubsub)

### Naming the Component

The class name is not necessarily important. However, it is important to **give it a component name prefixed with "sonic"** (or a prefix of your own) using the dedicated metadata already present in the copied document. For example, a button component would be named as follows:


<sonic-code language="typescript">
  <template>
@customElement("sonic-button")
  </template>
</sonic-code>

For less generic components with a specific destination, we advise to include the destination in the name.
For example, for a "title" component in the "event" destination, the name would be simply:


<sonic-code language="typescript">
  <template>
@customElement("sonic-event-title")
  </template>
</sonic-code>


## Modifying It

#### Creating Reactive Properties and Modifying the Render Function

To do this, study the functioning of https://lit.dev and also refer to [Subscriber](#docs/_core-concept/subscriber.md/subscriber).

#### HTML Structure of a Component

The HTML structure of a component should remain as simple as possible.

Ideally, there should be only one additional level of elements in addition to slots.

- **The main component is already a wrapper**.
  It receives classes to manage its layout, but it should not style internal elements.
- **Slots handle the visual organization** of elements.
- **The specificity of the component is expressed in this additional level** by adding a list, a functional native element (e.g., button), or another component.

This leads to the creation of more components and thus raises questions about the hierarchical organization of files. However, this tends to atomize their roles.

## Referencing It

To compile the component, it needs to be referenced somewhere through an import statement. In particular, it is important to reference it in any component that uses it.

In the case where it can be directly used in a page, it should also be globally referenced, especially considering the creation of **specific bundles** in the future.

Here's where we add imports based on the component's location inside concorde as an example

- **/core/components/functional/component-name/component-name.ts**  
  In `/core/components/functional/functional.ts`, which is referenced in core.ts and imported in `index.ts`.
- **/core/components/ui/component-name/component-name.ts**  
  In `/core/components/ui/ui.ts`, which is referenced in core.ts and imported in `index.ts`.
- **la-billetterie/components/atoms/component-name/component-name.ts**  
  Nowhere else but where it will be used, except for possible **temporary** tests, for example, in `index.ts`.
- **la-billetterie/components/concrete-destination/component-name/component-name.ts**  
  In `la-billetterie/components/concrete-destination/destination-concrete.ts`. 
  If it's a new destination, you'll need to create the corresponding import .ts file and import it in `la-billetterie.ts`.

## Using It

As a reminder, the component is simply integrated into the context by adding a tag with the component's name, for example:


<sonic-code language="html">
  <template>
<sonic-event-title></sonic-event-title>
  </template>
</sonic-code>