{"id":13850255,"url":"https://github.com/nicojs/typed-html","last_synced_at":"2025-04-09T07:03:28.427Z","repository":{"id":20390361,"uuid":"88642597","full_name":"nicojs/typed-html","owner":"nicojs","description":"TypeSafe HTML templates using TypeScript. No need to learn a template library.","archived":false,"fork":false,"pushed_at":"2024-08-02T20:01:38.000Z","size":943,"stargazers_count":345,"open_issues_count":24,"forks_count":49,"subscribers_count":7,"default_branch":"master","last_synced_at":"2024-10-29T21:01:50.307Z","etag":null,"topics":["html","template-engine","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nicojs.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-04-18T15:43:42.000Z","updated_at":"2024-10-20T14:30:52.000Z","dependencies_parsed_at":"2024-05-30T10:54:41.160Z","dependency_job_id":"4114bcec-2313-417e-93b7-2c4ea87680ba","html_url":"https://github.com/nicojs/typed-html","commit_stats":{"total_commits":73,"total_committers":6,"mean_commits":"12.166666666666666","dds":"0.15068493150684936","last_synced_commit":"88a6a6219bbf4d9368537ee29419d29671573093"},"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nicojs%2Ftyped-html","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nicojs%2Ftyped-html/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nicojs%2Ftyped-html/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nicojs%2Ftyped-html/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nicojs","download_url":"https://codeload.github.com/nicojs/typed-html/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247994120,"owners_count":21030050,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["html","template-engine","typescript"],"created_at":"2024-08-04T20:01:02.182Z","updated_at":"2025-04-09T07:03:28.403Z","avatar_url":"https://github.com/nicojs.png","language":"TypeScript","readme":"[![Build Status](https://travis-ci.org/nicojs/typed-html.svg?branch=master)](https://travis-ci.org/nicojs/typed-html)\n\n# Typed HTML\n\nHTML templates have never been this easy. Type safe using plain TypeScript with a minimal runtime footprint.\nNo need to learn a template language, if you know TypeScript, you're set.\n\nThis:\n\n```typescript\n// example.tsx\nconst item = 'item';\nconst icon = 'icon-add';\nconst ul = \u003cul\u003e\n    \u003cli\u003e{item}\u003c/li\u003e\n\u003c/ul\u003e;\n\ntypeof ul; // string\n\nconst button = \u003cbutton onclick=\"handleClick\"\u003e\n    \u003ci class={icon}\u003e\u003c/i\u003e\n\u003c/button\u003e;\n\ntypeof button; // string\n\nconsole.log(ul);\nconsole.log(button);\n```\n\nPrints: \n\n```html\n\u003cul\u003e\n    \u003cli\u003eitem\u003c/li\u003e\n\u003c/ul\u003e\n\u003cbutton onclick=\"handleClick\"\u003e\n    \u003ci class=\"icon-add\"\u003e\u003c/i\u003e\n\u003c/button\u003e\n```\n\n## Getting started\n\nInstall:\n\n```bash\nnpm install --save typed-html\n```\n\nConfigure your TypeScript compiler for JSX:\n\n```json\n{\n    \"compilerOptions\": {\n        \"jsx\": \"react\",\n        \"jsxFactory\": \"elements.createElement\"\n    }\n}\n```\n\nAlthough we're configuring the compiler to use [React](https://facebook.github.io/react), this is not what is being used.\nInstead, we redirect all jsx element to typed-html's `elements.createElement`.\n\nNow create a \\*.ts**x** file. For example: `example.tsx` with the following content:\n\n```typescript\n// example.tsx\nimport * as elements from 'typed-html';\n\nconst w = 'world';\nconst helloWorld = \u003cp\u003eHello \u003cstrong\u003e{w}\u003c/strong\u003e\u003c/p\u003e;\n\ntypeof helloWorld; // =\u003e Just a string of course\n```\n\nHowever, the following piece of code will **NOT** compile:\n\n```typescript\n\u003cfoo\u003e\u003c/foo\u003e; // =\u003e Error: Property 'foo' does not exist on type 'JSX.IntrinsicElements'.\n\u003ca foo=\"bar\"\u003e\u003c/a\u003e; // =\u003e Error:  Property 'foo' does not exist on type 'HtmlAnchorTag'\n```\n\n## Supported environments\n\nTyped HTML supports both NodeJS and (since 2.0) the browser.\n\nFor use in the browser, either load typed-html as a module, or use a bundler like webpack or rollup to bundle the package for you.\n\n```ts\n// Direct ES import:\nimport * as elements from './node_modules/typed-html/dist/elements.js';\n// OR, when using a bundler like rollup or webpack\nimport * as elements from 'typed-html';\n```\n\n## Supported scenarios\n\nAll template scenarios are supported with plain TypeScript.\n\n### Control flow\n\nConditional template with `?`\n\n```typescript\n\u003cdiv\u003eRandom \u003e 0.5: {Math.random() \u003e .5 ? \u003cstrong\u003eyes\u003c/strong\u003e : 'no'}\u003c/div\u003e\n```\n\nRepeat a template with `Array.map`\n\n```typescript\nconst items = ['item', 'item2'];\n\u003cul\u003e\n    {items.map(i =\u003e \u003cli\u003e{i}\u003c/li\u003e)}\n\u003c/ul\u003e;\n```\n\n### Helper templates\n\nWant a helper template? Just call a function\n\n```typescript\nfunction listItem(n: number) {\n    return \u003cli\u003e{n}\u003c/li\u003e;\n}\n\u003cul\u003e\n    {[1, 2].map(listItem)}\n\u003c/ul\u003e\n```\n\n#### Using a helper template like an element\n\nWant a helper component? Create a function that implements CustomElementHandler and you can call it like an HTML element. \n\n```typescript\nimport {Attributes, CustomElementHandler} from \"typed-html\"\n\nfunction Button(attributes: Attributes | undefined, contents: string[]) {\n    return \u003cdiv\u003e\u003cbutton type=\"button\" class=\"original-class\" {...attributes}\u003e{contents}\u003c/button\u003e\u003c/div\u003e;\n}\n// Or \nconst Button: CustomElementHandler = (attributes, contents) =\u003e \u003cdiv\u003e\u003cbutton type=\"button\" class=\"original-class\" {...attributes}\u003e{contents}\u003c/button\u003e\u003c/div\u003e;\n}\n    \nconsole.log(\u003cButton style=\"color:#f00\"\u003eButton Text\u003c/Button\u003e);\n```\n\nPrints: \n\n```html\n\u003cdiv\u003e\n    \u003cbutton type=\"button\" class=\"original-class\" style=\"color:#f00\"\u003eButton Text\u003c/button\u003e\n\u003c/div\u003e\n```\n\n#### React-style children\n\nIt's possible to write React-style components as well. Consider the example below.\n\n```typescript\nimport {Attributes, CustomElementHandler} from \"typed-html\"\n\nfunction Button({ children, ...attributes }: Attributes) {\n    return \u003cdiv\u003e\u003cbutton type=\"button\" class=\"original-class\" {...attributes}\u003e{children}\u003c/button\u003e\u003c/div\u003e;\n}\n\nconsole.log(\u003cButton style=\"color:#f00\"\u003eButton Text\u003c/Button\u003e);\n```\n\nPrints:\n\n```html\n\u003cdiv\u003e\n    \u003cbutton type=\"button\" class=\"original-class\" style=\"color:#f00\"\u003eButton Text\u003c/button\u003e\n\u003c/div\u003e\n```\n\n## Sanitization\n\nSecurity is *NOT* a feature. This library does *NOT* sanitize.\n\n```ts\nconst script = '\u003cscript\u003ealert(\"hacked!\")\u003c/script\u003e';\nconst body = \u003cbody\u003e{script}\u003c/body\u003e;\n```\n\nWill result in:\n\n```html\n\u003cbody\u003e\u003cscript\u003ealert('hacked!');\u003c/script\u003e\u003c/body\u003e\n```\n\nIf you need sanitization, you can use something like [sanitize-html](https://www.npmjs.com/package/sanitize-html).\n\n## Supported HTML\n\nAll HTML elements and attributes are supported, except for the [svg](https://www.w3.org/TR/SVG/).\n\n* Supported html elements: https://dev.w3.org/html5/html-author/#the-elements\n* Supported html events: http://htmlcss.wikia.com/wiki/HTML5_Event_Attributes\n\nMissing an element or attribute? Please create an issue or a PR to add it. It's easy to add.\n\n### Void elements\n\n[Void elements](https://www.w3.org/TR/html51/syntax.html#void-elements) (elements without closing tags) are supported, however you should close them in TypeScript.\n\n```typescript\nconst img = \u003cimg href=\"/foo/bar.png\"\u003e; // =\u003e Error! JSX element 'img' has no corresponding closing tag.\n``` \n\nIn the example above, closing the image tag is required for valid TSX code:\n\n```typescript\nconst img = \u003cimg href=\"/foo/bar.png\"\u003e\u003c/img\u003e; // =\u003e '\u003cimg href=\"/foo/bar.png\"\u003e'\n```\n\nSee [this code](https://github.com/nicojs/typed-html/blob/master/src/elements.tsx#L68) for a list of supported void elements.\n\n### Attribute types\n\nAll HTML attributes support a string value, however some attributes also support a [`number`](https://www.w3.org/TR/html51/infrastructure.html#numbers), [`Date`](https://www.w3.org/TR/html51/infrastructure.html#dates-and-times) or [`boolean`](https://www.w3.org/TR/html51/infrastructure.html#sec-boolean-attributes)(or absent value) type:\n\n```typescript\n\u003cmeter value={1} min={0} max={5} low={1} high={4} optimum={3}\u003e\u003c/meter\u003e; \n// =\u003e \u003cmeter value=\"1\" min=\"0\" max=\"5\" low=\"1\" high=\"4\" optimum=\"3\"\u003e\u003c/meter\u003e\n\u003col start={3}\u003e\u003c/ol\u003e;\n\u003cprogress value={3} max={4}\u003e\u003c/progress\u003e;\n\u003ctd colspan={3} rowspan={3}\u003e\u003c/td\u003e;\n\u003cth colspan={3} rowspan={3}\u003e\u003c/th\u003e;\n\nconst date = new Date('1914-12-20T08:00');\n\u003ctime datetime={date}\u003e\u003c/time\u003e; \n// =\u003e \u003ctime datetime=\"1914-12-20T08:00:00.000Z\"\u003e\u003c/time\u003e\n\u003cins datetime={date}\u003eupdated\u003c/ins\u003e;\n\u003cdel datetime={date}\u003eold\u003c/del\u003e;\n\n// =\u003e \u003cform\u003e \u003cinput type=\"checkbox\" checked\u003e \u003c/form\u003e\n\u003cform novalidate={false}\u003e \n    \u003cinput type=\"checkbox\" checked disabled={false}\u003e\u003c/input\u003e\n\u003c/form\u003e\n```\n\n## Custom elements\n\nYou can add custom elements by adding them to the [intrinsic elements](https://www.typescriptlang.org/docs/handbook/jsx.html#intrinsic-elements) yourself:\n\n```typescript\n// MyCustomElements.d.ts\n\ndeclare namespace JSX {\n    interface CustomElement {\n        customAttribute?: string;\n    }\n    interface IntrinsicElements {\n        myCustomElement: CustomElement;\n    }\n}\n```\n\nNow you can use it:\n\n```typescript\n// UseCustomElement.ts\nimport * as elements from 'typed-html';\n\nconst myElement = \u003cmyCustomElement customAttribute=\"customValue\"\u003e\u003c/myCustomElement\u003e\nconsole.log(myElement);\n```\n\nThis prints:\n\n```html\n\u003cmy-custom-element custom-attribute=\"customValue\"\u003e\u003c/my-custom-element\u003e\n```\n\n### Custom attributes\n\nCustom attribute names are already supported out-of-the-box for attributes with a dash (`-`) in the name. For example: \n\n```typescript\n\u003cbutton data-menu-item=\"3\"\u003e\u003c/button\u003e\n```\n\n### Transformation\n\nAs a browser is case insensitive when it comes to element and attribute names, it is common practice to use [kebab case](https://en.wikipedia.org/wiki/Letter_case#Special_case_styles) for this. However `\u003ccustom-element\u003e\u003c/custom-element\u003e` is not allowed in TypeScript. Therefore `typed-html` will transform `\u003ccustomElement\u003e\u003c/customElement\u003e` to `\u003ccustom-element\u003e\u003c/custom-element\u003e`.\n\nThis transformation also works for custom attributes you define on a custom element yourself. For example:\n\n```typescript\n\u003ccustomElement aCustomAttr=\"value\"\u003e\u003c/customElement\u003e\n```\n\nBecomes\n\n```html\n\u003ccustom-element a-custom-attr=\"value\"\u003e\u003c/custom-element\u003e\n``` \n\n## How this all works\n\nThe way this works is by using TypeScript's jsx support, but not for jsx/react interoperability. Instead, it defines the *normal* html tags as `IntrinsicElements` in the JSX namespace.\n\nAt runtime, the `elements.createElement` function is called for every html tag. It simply converts the given element to a string with minimal overhead.\n\nThis:\n\n```typescript\n\u003col start={2}\u003e{[1, 2].map(i =\u003e \u003cli\u003e{i}\u003c/li\u003e)}\u003c/ol\u003e\n```\n\nCompiles to:\n\n```javascript\nelements.createElement(\"ol\", { start: 2 }, [1, 2].map(function (li) { \n    return elements.createElement(\"li\", null, li); \n}));\n```\n\nWhich translates to:\n\n```html\n\u003col start=\"2\"\u003e\n    \u003cli\u003e1\u003c/li\u003e\n    \u003cli\u003e2\u003c/li\u003e\n\u003c/ol\u003e\n```","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnicojs%2Ftyped-html","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnicojs%2Ftyped-html","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnicojs%2Ftyped-html/lists"}