# DOM style injection

Some users may want to inject their styles into the DOM like v1. There is no equivalent for this functionality in the second version so we can define our `injectStyle` function as following:

```typescript
// inject-style.ts

function caseConverter(str: string): string {
  if (str.length === 0) return str;
  const isUppercase = str[0] === str[0].toUpperCase();
  const result = str
    .split(/(?=[A-Z])/)
    .join("-")
    .toLowerCase();
  return isUppercase ? `-${result}` : result;
}

// CSS object to string converter.
export function toCss(obj: any): string {
  if (!obj || typeof obj !== "object" || Array.isArray(obj)) {
    throw new TypeError(
      `expected an argument of type object, but got ${typeof obj}`
    );
  }
  let lines: string[] = [];
  for (let index = 0; index < Object.keys(obj).length; index++) {
    const id = Object.keys(obj)[index];
    const key = caseConverter(id);
    const value = obj[id];
    if (typeof value === "object") {
      const text = toCss(value);
      lines.push(`${id}{${text}}`);
    } else {
      lines.push(`${key}:${value};`);
    }
  }
  return lines.join("");
}

// Inject string/object style to DOM.
export function injectStyle(
  textOrObject: string | object,
  id?: string,
  overridable = true,
  hostElement: HTMLElement = document.head
) {
  if (!textOrObject || Array.isArray(textOrObject)) return;
  if (typeof textOrObject === 'string' && textOrObject.length === 0) return;
  if (id) {
    let oldStyle = document.getElementById(id);
    if (oldStyle) {
      let isStyleTag = oldStyle.tagName.toLowerCase() === "style";
      if (!isStyleTag) {
        throw new Error("The provided id does not indicate a style tag.");
      } else if (isStyleTag && overridable) {
        oldStyle.innerHTML = typeof textOrObject === "object" ? toCss(textOrObject) : textOrObject;
      }
      return;
    }
  }
  let style = document.createElement("style");
  style.type = "text/css";
  style.innerHTML = typeof textOrObject === "object" ? toCss(textOrObject) : textOrObject;
  if (id) style.id = id;
  hostElement.appendChild(style);
}
```

## toCss(obj)

A very simple object-to-css converter.

| Parameter(s) | Description        | Optional | Default |
| ------------ | ------------------ | :------: | :-----: |
| obj          | Object-based style |    No    |    -    |

**Returns**: a css text.

```javascript
// css-object-style.ts

export const cssObj = {
  ".main-wrapper": { flexDirection: "row", display: "flex", flex: "1" },
  "#content": { flex: "1" },
  ul: { padding: "20px 0", flex: "1" },
  li: { fontFamily: "'Lato'", color: "whitesmoke", lineHeight: "44px" }
};

let cssText = toCss(cssObj);
```

The value of `cssText` will be equal to:

```css
.main-wrapper {
  flex-direction: row;
  display: flex;
  flex: 1;
}
#content {
  flex: 1;
}
ul {
  padding: 20px 0;
  flex: 1;
}
li {
  font-family:'Lato';
  color: whitesmoke;
  line-height: 44px;
}
```

You can use [css-to-js transformer](https://transform.tools/css-to-js) to convert a CSS text to a JS object and use the result for `toCss(result)` directly!

There is a conventional naming approach for defining your rules. Every uppercase character will change to a hyphen and a lowercase character (`XyZ => -xy-z`). For example, If you want to achieve `-webkit-animation` you should write `WebkitAnimation` or `flexDirection` will change to `flex-direction`.

This is exactly what the `caseConverter` function does.

## injectStyle(textOrObject, id, overridable, hostElement)

A functionality to inject your text or object-based style to the html document easily!

| Parameter(s) | Description                                                                                                   | Optional |    Default    |
| ------------ | ------------------------------------------------------------------------------------------------------------- | :------: | :-----------: |
| textOrObject | Text or object-based style.                                                                                   |    No    |       -       |
| id           | To set an id for your `<style>`, it helps you to update an specific style tag.                                |    Yes   |       -       |
| overridable  | If set this to `false`, your style is only injected **once** but to do this you must set an id parameter too. |    Yes   |      true     |
| hostElement  | To set your host element to inject your style into it. Useful for shadow DOM.                                 |    Yes   | document.head |

```javascript
import { injectStyle } from 'inject-style';
import { cssObj } from 'css-object-style';

// Object
injectStyle(cssObj, 'my-style-tag', false);

// String
injectStyle(`
.main-wrapper {
  flex-direction: row;
  display: flex;
  flex: 1;
}
#content {
  flex: 1;
}
ul {
  padding: 20px 0;
  flex: 1;
}
li {
  font-family:'Lato';
  color: whitesmoke;
  line-height: 44px;
}
`, 'my-style-tag', false);
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.aurelia.io/~/revisions/NShYVVc01DvYc5bgBiwq/developer-guides/scenarios/dom-style-injection.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
