{"id":41326574,"url":"https://github.com/stephancasas/presto","last_synced_at":"2026-01-23T06:08:46.766Z","repository":{"id":57329935,"uuid":"334082710","full_name":"stephancasas/presto","owner":"stephancasas","description":"HTML componentization, specialized for Alpine JS.","archived":false,"fork":false,"pushed_at":"2021-02-27T06:58:15.000Z","size":649,"stargazers_count":27,"open_issues_count":2,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-10-02T03:58:45.900Z","etag":null,"topics":["alpine","alpinejs","componentization","components","html"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stephancasas.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":["stephancasas"]}},"created_at":"2021-01-29T08:29:00.000Z","updated_at":"2025-01-30T20:14:40.000Z","dependencies_parsed_at":"2022-09-13T21:11:32.276Z","dependency_job_id":null,"html_url":"https://github.com/stephancasas/presto","commit_stats":null,"previous_names":["stephancasas/snowblade"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/stephancasas/presto","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stephancasas%2Fpresto","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stephancasas%2Fpresto/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stephancasas%2Fpresto/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stephancasas%2Fpresto/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stephancasas","download_url":"https://codeload.github.com/stephancasas/presto/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stephancasas%2Fpresto/sbom","scorecard":{"id":851246,"data":{"date":"2025-08-11","repo":{"name":"github.com/stephancasas/presto","commit":"3dbc40ccd8940b92d8d370648dac0168bdb89a89"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.9,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":9,"reason":"1 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-gcx4-mw62-g8wm"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-23T22:37:11.099Z","repository_id":57329935,"created_at":"2025-08-23T22:37:11.099Z","updated_at":"2025-08-23T22:37:11.099Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28681917,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-23T05:48:07.525Z","status":"ssl_error","status_checked_at":"2026-01-23T05:48:07.129Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["alpine","alpinejs","componentization","components","html"],"created_at":"2026-01-23T06:08:45.954Z","updated_at":"2026-01-23T06:08:46.746Z","avatar_url":"https://github.com/stephancasas.png","language":null,"funding_links":["https://github.com/sponsors/stephancasas"],"categories":[],"sub_categories":[],"readme":"[]()\n\u003cp align=\"center\"\u003e\u003cimg src=\"https://get.stephancasas.com/static/presto-logo.png\" width=\"45%\"\u003e\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\u003ci\u003e\u003cstrong\u003eSyntactically-natural, \"magic\" markup componentization — specialized for Alpine JS.\u003c/strong\u003e\u003c/i\u003e\u003c/p\u003e\n\n# Presto JS — *Utility Preview*\n\nPresto offers you componentization of HTML elements — similar to the import/export nature of ES6 modules.\n\nThink of it like [Rollup](https://github.com/rollup/rollup) for HTML.\n\n\u003e Presto is currently under active **initial development** and available only for preview in its compiled \"dist\" state. As such, pull requests are not being considered at this time. However, bug reports, feedback, and feature requests are encouraged — the goal of this repository is to create an open discussion. Please submit any considerations of this nature as [issues here on GitHub](https://github.com/stephancasas/presto/issues).\n\n\u003cp align=\"center\"\u003e\u003cimg src=\"https://get.stephancasas.com/static/presto-hero-20200211.png\" width=\"85%\"\u003e\u003c/p\u003e\n\n## Why?\n\nPresto was inspired by [Alpine.js](https://github.com/alpinejs/alpine), which offers developers the ability to leverage a fully-reactive framework via attributes sprinkled into your existing markup like `x-for`, `x-text`, or `x-on:click`. Using Alpine in-tandem with utility frameworks like [Tailwind CSS](https://github.com/tailwindlabs/tailwindcss), developers can rapidly build complete app frontends with little overhead and often without ever writing more than a single `.html` file. \n\nThis ease of use has the potential to come at a cost however, as the HTML source starts to grow very rapidly and with considerable redundancy — especially for SPA-type applications.\n\nThe goal of Presto is to break-down your app's HTML into smaller and reusable components without forcing you into adopting a new syntax like Vue or React's JSX. Already have most of your frontend built? Great! Presto works with the HTML you already have. All you have to do is extract the components that you want to reuse and organize.\n\n\u003e #### Why not use React or Vue?\n\u003e As developers, we each typically have a framework of choice when it comes to creating application views. Each framework comes with its own idiosyncracies; workflows; dependencies; and, often times, a learning curve. Tools like Alpine and Tailwind CSS leverage the universal familiarity of HTML and enable developers to accomplish a bulk of their frontend development in one place, the markup — an approach that is both rapid and increasingly \"instinctive\" in its execution.\n\u003e\n\u003e Presto aims to build on that universal familiarity and seeks to make mangement of frontend components syntactically-natural, central, and accessible to everyone.\n\n## Demo App and Video Intro\n\nIf you're like most developers and prefer to learn through examples, the Presto demo app, Expresslane, is [available here](https://github.com/stephancasas/presto-demo-app), and the intro video can be [viewed on YouTube here](https://www.youtube.com/watch?v=HRWVUiWx-dA).\n\n## Install\n\n**From npm:** Install the CLI tool from npm.\n\n```sh\nnpm i presto --save-dev\n```\n\n## Config\n\nInside of a Node environment, Presto is a command line utility accessible using the npm command `presto` with a configuration file that you specify. Create a `presto.config.js` file in your project's root:\n\n\u003cp align=\"right\"\u003e\u003cstrong\u003e\u003ccode\u003epresto.config.js\u003c/code\u003e\u003c/strong\u003e\u003c/p\u003e\n\n```js\n// REQUIRED : Object | Array\u003cObject\u003e\nexport default {\n    // REQUIRED : string\n    // Where to begin compiling -- this should be where your \u003cbody\u003e element is\n    input: 'resources/presto/views/index.html',\n    \n    // Optional : Array\u003cstring\u003e | string\n    // Path(s) to components that should be universally available\n    include: [\n        'resources/presto/shared/**/*.html'\n    ],\n    \n    // REQUIRED : Object | Array\u003cObject\u003e\n    // Specifies the compiled output path and its property variations\n    output: {\n        // REQUIRED: string\n        // Specifies the compiled output path\n        file: 'resources/views/index.html',\n        \n        // Optional : Object [{} (default)]\n        // Specifies property values which are globally-available to components\n        // without requiring redundant application on component expressions\n        // (e.g. colours, sizes, etc.)\n        props: {\n            buttonColor: 'red',\n        },\n        \n        // Optional : Object [{} (default)]\n        // Specifies, as an object of functions accepting a single argument,\n        // functions which manipulate the computation of expression properties\n        pipes: {\n            TailwindMxAlign(arg) {\n                return {\n                    left: 'mr-auto',\n                    center: 'mx-auto',\n                    right: 'ml-auto'\n                }[arg === '' ? 'center' : arg];\n            }\n        }\n    }\n}\n```\n\n###  `npx presto --init`\n\nTo provision a basic configuration file, with optional sample components, you can use the `--init` option in your project's directory:\n\n```sh\nnpx presto --init\n```\n\n### Extending the Config File\n\nBy using a JS file as the configuration object, Presto enables developers the ability to leverage the object-oriented nature of JavaScript. In this way, you can declare things like `include`, `props`, or `pipes` as constants, and then pass them into as many or as few `config` objects that need them:\n\n\n\u003cp align=\"right\"\u003e\u003cstrong\u003e\u003ccode\u003epresto.config.js\u003c/code\u003e\u003c/strong\u003e\u003c/p\u003e\n\n```js\nconst include = [\n    'resources/presto/shared/**/*.html'\n];\n\nconst props = {\n    buttonColor: 'red',\n    background: 'bg-gray-100'\n};\n\nconst pipes = {\n    TailwindMxAlign(arg) {\n        return {\n            left: 'mr-auto',\n            center: 'mx-auto',\n            right: 'ml-auto'\n        }[arg === '' ? 'center' : arg];\n    }\n};\n\nexport default [\n    {\n        input: 'resources/presto/views/app.html',\n        include, // assigned from const\n        output: {\n            file: 'resources/views/app.html',\n            props, // assigned from const\n            pipes, // assigned from const\n        }\n    },\n    \n    /* ... */\n    \n    {\n        input: 'resources/presto/views/dashboard.html',\n        include, // assigned from const\n        output: {\n            file: 'resources/views/dashboard.html',\n            props, // assigned from const\n            pipes, // assigned from const\n        }\n    }\n]\n\n```\n\n## Usage\n\nWhen run on its own, the `presto` command, by default, will look in your project's root directory for a `presto.config.js` file. If you wish to specify a different file for various build types, you may use the `--config` or `-c` switch to specify a different config:\n\n```sh\npresto --config presto.config.prod.js\npresto --config presto.config.dev.js\n```\n\nAs part of your development workflow, Presto can be used with `npm-run-all` to compile your DOM with each build:\n\n**Example in TypeScript environment:**\n```json\n\"scripts\": {\n    \"compile:dom\": \"presto --config presto.config.js\",\n    \"transpile\": \"tsc -p ./tsconfig.json\",\n    \"clean\": \"rimraf ./dist\",\n    \"build\": \"npm-run-all clean transpile compile:dom\"\n}\n```\n\n### File-watching with [Nodemon](https://github.com/remy/nodemon/)\n\nEventually, the intention is to use implement the [Chokidar](https://github.com/paulmillr/chokidar) file-watcher library to allow for a single command, `presto --watch`, to run in the background during component development. In this way, as each component is modified and saved, Presto will recompile to reflect changes.\n\nFor now, your development workspace can be configured to work with [Nodemon](https://github.com/remy/nodemon/) watching your Presto directory:\n\n\u003cp align=\"right\"\u003e\u003cstrong\u003e\u003ccode\u003epackage.json\u003c/code\u003e\u003c/strong\u003e\u003c/p\u003e\n\n```json\n{\n    \"scripts\": {\n        \"watch\": \"nodemon --watch ./src/presto -e html --exec \\\"npx presto\\\"\",\n    }\n}\n```\n\n## Overview\n\nExpression of components in Presto starts by declaring a component definition with native HTML, and then expressing that component in your markup through use of a syntactically-natural custom tag that you define. Starting from the `input` document in your config, your markup will be compiled as each component is referenced, expressed, and rendered.\n\n### Input Documents\n\nPresto output begins with one item, an input document specified as the `input` property of a config object in `presto.config.js`. From this input document, Presto will cascade through any component expressions and render them as HTML where they are written. A sample input document might look something like this:\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003clink presto href=\"../components/app.html\"\u003e\n\u003clink presto href=\"../components/documenthead.html\"\u003e\n\u003chtml\u003e\n    \u003chead\u003e\n        \u003cDocumentHead /\u003e\n    \u003c/head\u003e\n    \u003cbody class=\"w-screen h-screen\"\u003e\n        \u003cApp /\u003e\n    \u003c/body\u003e\n\u003c/html\u003e\n```\n\nAs promised, the syntax is plain old HTML. The only difference is that we've included components for Presto to reference and render. This is first done by referencing the components using standard `\u003clink\u003e` tags with an empty `presto` attribute:\n\n```html\n\u003clink presto href=\"./components/app.html\"\u003e\n\u003clink presto href=\"./components/documenthead.html\"\u003e\n```\n\nThink of these `\u003clink\u003e` tags like ES6 `import` statements. Next, the components are told where to render within the document by expressing each component's custom tag:\n\n```html\n\u003c!-- ... --\u003e\n    \u003cDocumentHead /\u003e\n\u003c!-- ... --\u003e\n    \u003cApp /\u003e\n\u003c!-- ... --\u003e\n```\n\n\n\u003e #### Why use a generic `\u003clink\u003e` tag instead of a custom tag?\n\u003e To take advantage of IDE and editor logic/formatting. Most editors' language servers will offer auto-completion of paths expressed on the `href` attribute of a `\u003clink\u003e` tag. This makes it easier for you to ensure that you've typed the correct path to your imported component.\n\u003e \n\u003e Eventually, I'd like to extend the existing HTML LSP-compliant language server in VSCode to help with auto-completion of component names and, where necessary, rewriting of component imports when project assets are reorganized. If anyone reading this has experience with LSP in VSCode, and would like to help, please [contact me via DM on Twitter](https://www.twitter.com/stephancasas).\n\n#### Config-provided Components\n\nIf you've defined a string or array of strings on the `include` property of `presto.config.js`, you don't need to express your component imports using `\u003clink\u003e` tags for those component documents which match your given [Glob](https://github.com/isaacs/node-glob) patterns. In the case that a config-provided component has a name conflict with an import-provided component expressed via `\u003clink\u003e` tag, Presto will use the import-provided component when resolving a component expression.\n\n\u003e #### Unique Component Names\n\u003e \n\u003e While making use of import-provided components allows for duplicating component names, this is a  practice against which I strongly recommend in most cases. However, an exception to this could be if you were defining a custom table component. In such an instance, you may want to have `\u003cCell\u003e Data \u003c/Cell\u003e` expressed differently under `\u003cTableHeader\u003e` than you would if it were expressed under `\u003cTableRow\u003e`.\n\n---\n\n### :rotating_light: Readme/Documentation Pragma :rotating_light:\nThe remainder of this README will be written under the assumption that all components are *import-provided*, but it should be noted that this is **not necessary**, and you can provide **all** of your components using the `include` property on your config object, making things much easier. Use Presto how you want to use it, in whatever way makes your project easier.\n\n---\n\n### Component Documents\n\nThe input document example included a link to the component `./app.html` and then expressed it as `\u003cApp /\u003e` within the markup. For this to render correctly, there needs to be a component file present at `./app.html`, relative to the index document:\n\n\u003cp align=\"right\"\u003e\u003cstrong\u003e\u003ccode\u003eapp.html\u003c/code\u003e\u003c/strong\u003e\u003c/p\u003e\n\n```html\n\u003cmeta presto name=\"App\"\u003e\n\u003clink presto href=\"./components/modal.html\"\u003e\n\u003clink presto href=\"./components/sidebar.html\"\u003e\n\u003clink presto href=\"./components/navigation.html\"\u003e\n\u003clink presto href=\"./components/editor.html\"\u003e\n\n\u003cdiv class=\"flex flex-col h-screen\"\u003e\n    \u003cModal /\u003e\n    \u003cNavigation /\u003e\n    \u003cdiv class=\"flex flex-1 items-center\"\u003e\n        \u003cSidebar class=\"w-32\"/\u003e\n        \u003cEditor class=\"flex-1\" /\u003e\n    \u003c/div\u003e\n\u003c/div\u003e\n```\n\nA lot is happening here, but let's start from the top to understand what's being expressed. Most critically, the component document starts with a `\u003cmeta\u003e` tag that provides a handle for the component we're defining — in this case, we're defining an *app* component that will be expressed as `\u003cApp /\u003e`, so the `name` attribute of our tag is set to `\"App\"`. The full tag is expressed as:\n\n```html\n\u003cmeta presto name=\"App\"\u003e\n```\n\nFor each component name, use of PascalCase (like ES6 classes) is recommended to aid in syntactic visibility, but this is optional and completely up to you. Presto component tags **are case-sensitive**, so if you declare a component as `App`, it must be expressed as `\u003cApp /\u003e`, and not as `\u003capp /\u003e`.\n\n\u003e #### Case-insensitive Code Formatters\n\u003e \n\u003e Some code formatters will drop capital letters in HTML tag names, especially those names which match existing standards-compliant tags. While Presto recognizes the difference between `\u003cHead\u003e` and `\u003chead\u003e` or `\u003cTable\u003e` and `\u003ctable\u003e`, you may find that your code formatter replaces upper-cased tag names with lower-cased equivalents.\n\u003e \n\u003e If you're using [Prettier](https://github.com/prettier/prettier), you will not experience an issue with casing unless you attempt to express a component using an upper-case name that matches an existing standard HTML tag.\n\n#### Component Nesting\n\nBelow the `\u003cmeta\u003e` tag, several `\u003clink\u003e` tags have been specified. Each of these will correspond to a component document that expresses its export via a `\u003cmeta presto name=\"...\"\u003e`, similar to the one defined for the `App` component.\n\nWithin the body of the `App` component, there's a mix of native markup as well as Presto component expressions. In this way, a component can yield its HTML wherever it's needed in a document — nested inside of as many or as few expressions as is desired.\n\n### Component Attributes\n\nIn the example `App` component document, notice that the `Sidebar` and `Timeline` expressions have `class` attributes applied to them. In this case, we're making use of [Tailwind CSS](https://tailwindcss.com/) to define the width of each component inside of their parent `\u003cdiv\u003e`. This is a critical aspect of Presto and one that makes component reusability so versatile. To take a look at how this is applied, let's examine the content of an example `sidebar.html` component:\n\n```html\n\u003cmeta presto name=\"Sidebar\"\u003e\n\u003clink presto href=\"./notethumbnail.html\"\u003e\n\n\u003cdiv class=\"flex flex-col flex-1 h-0\"\u003e\n    \u003cdiv class=\"flex items-center p-2 text-xl\"\u003e\n        \u003cspan\u003eAll Notes\u003c/span\u003e\n    \u003c/div\u003e\n    \u003cdiv class=\"flex flex-col flex-1 h-0 pt-2 border-t gap-y-2 overflow-y-scroll\"\u003e\n        \u003cNoteThumbnail\n            ::showPreview\n            ::size=\"large\"\n            $$wrap=\"template\"\n            x-for=\"note in notes\"\n        /\u003e\n    \u003c/div\u003e\n\u003c/div\u003e\n```\n\nIf you're unfamiliar with Tailwind CSS, the classes we've applied to the inner `\u003cdiv\u003e` in `App` containing our `Sidebar` and `Editor` components provide for a space that occupies the entirety of the browser below the `Navigation` component — we'll call this space the *\"content\"* area. Then, the classes applied to the wrapping `\u003cdiv\u003e` in `Sidebar` provide for a space that occupies the entire height and width of the content area.\n\n\u003e *The `Modal` component is `position: absolute;` and does not count against our app's vertical space.\n\nHowever, the sidebar component is just that, a sidebar. It shouldn't occupy the *entire* content area – only a space to the side of it. By passing the `w-32` class in the `class` attribute for `Sidebar` in `App`, Presto will add `w-32` to the `class` attribute of the wrapping `\u003cdiv\u003e` in `Sidebar` when it renders its HTML for `App`. The Tailwind CSS class `w-32` will limit the width of `Sidebar` to `8rem`, leaving the remaining space in the content area to be occupied by `Editor`, on which we've applied a Tailwind CSS class of `flex-1`.\n\nIn this way, our sidebar component can be reused anywhere throughout our app. Attributes that need to be modified based on context can be applied onto the component expression itself rather than hard-coded into the component definition.\n\n### Component Wrapping - `$$wrap`\n\nLooking at the component document for `Sidebar`, you might have noticed that the component expression for `NoteThumbnail` is looking a little busy. In addition to applying an attribute for Alpine, `x-for`, the component expression also has a few attributes specific to Presto. To understand what each of these attributes does, let's look at the component document that the `NoteThumbnail` expression references:\n\n\u003cp align=\"right\"\u003e\u003cstrong\u003e\u003ccode\u003enotethumbnail.html\u003c/code\u003e\u003c/strong\u003e\u003c/p\u003e\n\n```html\n\u003cmeta\n    presto\n    name=\"NoteThumbnail\"\n    ::showPreview=\"hidden\"\n    ::showCheck=\"hidden\"\n    ::size=\"medium\"\n\u003e\n\n\u003cscript presto\u003e\n    function size(arg) {\n        return {\n            large: 'h-16',\n            medium: 'h-8',\n            small: 'h-4',\n        }[arg];\n    }\n\u003c/script\u003e\n\n\u003cdiv class=\"flex items-center p-2 {{ size | size}}\"\u003e\n    \u003cdiv class=\"flex items-center w-4 {{ showCheck }}\"\u003e\n        \u003cinput\n            type=\"checkbox\"\n            class=\"p-2 mx-auto\"\n        /\u003e\n    \u003c/div\u003e\n    \u003cdiv class=\"flex flex-col\"\u003e\n        \u003cdiv class=\"text-lg font-semibold\" x-text=\"note.header\"\u003e\u003c/div\u003e\n        \u003cdiv class=\"text-xs truncate {{ showPreview }}\" x-text=\"note.content\"\u003e\u003c/div\u003e\n    \u003c/div\u003e\n\u003c/div\u003e\n```\n\nConsidering the component definition for `App`, we already know that any attributes we apply to a component expression will be applied to the root element within that component. However, those familiar with Alpine know that the `x-for` attribute can only be applied to a `\u003ctemplate\u003e` element, and the component definition for `NoteThumbnail` uses a `\u003cdiv\u003e` as its root.\n\nWe could just wrap the root `\u003cdiv\u003e` inside of a `\u003ctemplate\u003e` within the component definition, but suppose we want to use our thumbnail component elsewhere within our app? With it wrapped inside of a `\u003ctemplate\u003e` tag, we might lose the ability to reuse it. Instead, the expression for `NoteThumbnail` in `Sidebar` applies the Presto `$$wrap` attribute, which will wrap the component definition in a specified tag (in this case, a `\u003ctemplate\u003e` tag) before applying any additional attribute logic. In this way, when the component's HTML is rendered, it will look like this:\n\n```html\n\u003ctemplate x-for=\"note in notes\"\u003e\n    \u003cdiv class=\"flex items-center p-2 h-16\"\u003e\n        \u003cdiv class=\"flex items-center w-4 hidden\"\u003e\n            \u003cinput\n                type=\"checkbox\"\n                class=\"p-2 mx-auto\"\n            /\u003e\n        \u003c/div\u003e\n        \u003cdiv class=\"flex flex-col\"\u003e\n            \u003cdiv class=\"text-lg font-semibold\" x-text=\"note.header\"\u003e\u003c/div\u003e\n            \u003cdiv class=\"text-xs truncate \" x-text=\"note.content\"\u003e\u003c/div\u003e\n        \u003c/div\u003e\n    \u003c/div\u003e\n\u003c/template\u003e\n```\n\nNotice that Presto applied the attribute `x-for` to the specified wrapper, and not directly onto the `\u003cdiv\u003e` inside the component definition. This is determined by the order in which attributes are declared. When using `$$wrap`, any attributes that are declared *after* `$$wrap` is established will be coalesced onto the wrapper element, and not onto the component's root element.\n\n### Component Properties — `{{ propName }}`\n\nExamining that output, did you notice anything else? The `class` attribute for the last `\u003cdiv\u003e` contained some mustache syntax as `{{ showPreview }}` which was rendered as: \n\n```html\n    \u003cdiv class=\"text-xs truncate \" x-text=\"note.content\"\u003e\u003c/div\u003e\n```\n\nThis is because a *property* was passed in the component expression for `NoteThumbnail` as `::showPreview`. Presto components can receive properties using the syntax `::propName=\"value\"` on a component expression. Within the component, these property values are yielded using property tokens:\n\n```html\n\u003c!-- Expressed as given --\u003e\n     {{ propName }}\n\n\u003c!-- Evaluated by pipe function before expression --\u003e\n     {{ propName | pipeName }}\n```\n\nWithin the `\u003cmeta\u003e` of the component definition, property defaults can be given that are used when the component expression is absent of said property:\n\n```html\n\u003cmeta\n    presto\n    name=\"NoteThumbnail\"\n    ::showPreview=\"hidden\"\n    ::showCheck=\"hidden\"\n    ::size=\"medium\"\n\u003e\n```\n\nFor the property `showPreview`, a default value of `\"hidden\"` is given (`display: none;` in Tailwind CSS), but on the component expression for `NoteThumbnail`, this is overriden to an empty value as `::showPreview`. In this way, you can make use of \"boolean-style\" properties for your components, where a truthy or falsy value is the property default that gets overriden by an empty value on a component expression.\n\n### Component Property Pipes — `{{ propName | pipeName }}`\n\nReviewing the component expression for `NoteThumbnail` you'll notice that the `::size` property was passed as `\"large\"`, but was rendered as:\n\n```html\n\u003cdiv class=\"flex items-center p-2 h-8\"\u003e\n```\n\nIn this case, before `size` was expressed, it was processed by a pipe — a function accepting a single argument and returning a string:\n\n```js\nfunction size(arg) {\n    return {\n        large: 'h-16',\n        medium: 'h-8',\n        small: 'h-4',\n    }[arg];\n}\n```\n\nPipes can be useful where you'd like to use more \"natural\" language to express complex strings of data. In `NoteThumbnail` it's being used to convert values of `large`, `medium`, and `small` into Tailwind CSS height classes. Back in the example `presto.config.js`, the pipe `TailwindMxAlign` is defined to convert `left`, `right`, and `center` into their margin equivalents — useful when making use of flexbox:\n\n```js\nTailwindMxAlign(arg) {\n    return {\n        left: 'mr-auto',\n        center: 'mx-auto',\n        right: 'ml-auto'\n    }[arg === '' ? 'center' : arg];\n}\n```\n\nAs you've probably noticed, there's two places where pipes can be defined. Where a pipe is only needed for a single component, it can be declared in a `\u003cscript\u003e` tag with an empty `presto` attribute, written inside of the component document. If a pipe is going to be reused in several components, it can be declared on the `pipes` property of the `output` property of `presto.config.js`.\n\n\u003e #### The `function` Keyword in Component-scoped Pipes\n\u003e \n\u003e If you're declaring a component-scoped pipe, you must declare your pipe at the root of `\u003cscript\u003e` and provide the `function` keyword right before the pipe declaration. Component-scoped pipes are converted to named exports and then transpiled by Babel. Don't worry — to save time, pipes are cached, and this process only takes place when you change something in the content of `\u003cscript presto\u003e\u003c/script\u003e`.\n\n## Slots\n\nComponent slots in Presto work exactly as you'd expect. As of this writing, Presto supports one type of slot — the *default* slot. Named slots are under consideration, so if you'd like to see more development on this, please suggest an implementation strategy by [raising an issue](https://github.com/stephancasas/presto/issues).\n\nWithin a component document, a default slot can be expressed using the `\u003cslot\u003e` tag with an empty `presto` attribute:\n\n```html\n\u003c!-- ... --\u003e\n    \u003cslot presto\u003e Some default content goes here. \u003c/slot\u003e\n\u003c!-- ... --\u003e\n```\n\nWhen using a component expression, the `\u003cslot\u003e` will be fulfilled by including markup between the expression's tags:\n\n```html\n\u003c!-- ... --\u003e\n    \u003cMyComponent\u003e\n        This is my slot content.\n    \u003c/MyComponent\u003e\n\u003c!-- ... --\u003e\n```\n\nIf no content is supplied, Presto will render the default content expressed between the `\u003cslot\u003e` tags in the component definition.\n\n### Slots and Properties\n\nSuppose you've defined a button component that you want to use with a slot:\n\n\u003cp align=\"right\"\u003e\u003cstrong\u003e\u003ccode\u003ebasicbutton.html\u003c/code\u003e\u003c/strong\u003e\u003c/p\u003e\n\n```html\n\u003cmeta presto name=\"BasicButton\" ::fill=\"green\" ::label ::width=\"full\" /\u003e\n\n\u003cbutton\n  type=\"button\"\n  class=\"py-2 px-4 bg-{{ fill }}-500 border border-{{ fill }}-500 hover:bg-{{ fill }}-400 text-white transition ease-in duration-200 text-center text-base font-semibold rounded-lg w-{{ width }}\"\n\u003e\n  \u003cslot presto\u003e{{ label }}\u003c/slot\u003e\n\u003c/button\u003e\n```\n\nWhen you use the `BasicButton` expression, you could fulfill the button's label in one of two ways:\n\n```html\n\u003c!-- Slot Fulfillment --\u003e\n\u003cBasicButton\u003e Click Me! \u003c/BasicButton\u003e\n\n\u003c!-- Property Value --\u003e\n\u003cBasicButton ::label=\"Click Me!\" /\u003e\n```\n\nThis works because slot processing is the second step that takes place when parsing a component expression — right after the `$$wrap` attribute is evaluated. Because the default slot content is the property token `{{ label }}`, Presto will have access to substitute a given value when evaluating the expression-assigned property `::label`.\n\n\u003e #### Why would you want to do this?\n\u003e \n\u003e Using a property token as the default slot content can be helpful if you want the ability to globally-manipulate a component's slotted content. Through the use of config-provided property values, you can manage slot content in one location.\n\u003e \n\u003e This is also really useful for when using *magic properties* with Alpine, so please keep reading!\n\n## Magic Properties\n\nSaving the best for last, magic properties are what make Presto the perfect companion for Alpine developers. Consider the `BasicButton` component definition described above. If you wanted to make it more \"Alpine-friendly,\" you could make some changes:\n\n```html\n\u003cmeta presto name=\"BasicButton\" ::fill=\"'green'\" ::label ::width=\"'full'\" /\u003e\n\n\u003cbutton\n  type=\"button\"\n  x-bind:class=\"`py-2 px-4 bg-${ {{ fill }} }-500 border border-${ {{ fill }} }-500 hover:bg-${ {{ fill }} }-400 text-white transition ease-in duration-200 text-center text-base font-semibold rounded-lg w-${ {{ width }} }`\"\n  x-text=\"{{ label }}\"\n\u003e\u003c/button\u003e\n```\n\nThen, when iterating with `x-for`, your component expression would look something like this:\n\n```html\n\u003c!-- ... --\u003e\n    \u003cBasicButton ::label=\"b.label\" ::fill=\"b.color\" ::width=\"'24'\" $$wrap=\"template\" x-for=\"b in buttons\" /\u003e\n\u003c!-- ... --\u003e\n```\n\nThat works, but it's less than ideal. In the component definition, you've had to do a lot of escaping and now, if you want to reuse the button outside of an Alpine context, you *can't* because `class` is declared as `x-bind:class` and the button's label is expressed as `x-text` rather than native HTML. *Additionally*, you now have to surround static property values with single quotes, like the default values for `fill` and `width`.\n\nIs there a better way? Of course there is.\n\n### A Little Bit of Magic :sparkles:\n\nLet's restore the original version of the `BasicButton` definition:\n\n```html\n\u003cmeta presto name=\"BasicButton\" ::fill=\"green\" ::label ::width=\"full\" /\u003e\n\n\u003cbutton\n  type=\"button\"\n  class=\"py-2 px-4 bg-{{ fill }}-500 border border-{{ fill }}-500 hover:bg-{{ fill }}-400 text-white transition ease-in duration-200 text-center text-base font-semibold rounded-lg w-{{ width }}\"\n\u003e\n  \u003cslot presto\u003e{{ label }}\u003c/slot\u003e\n\u003c/button\u003e\n```\n\nNow, instead of mangling the component definition, let's instead change the way that we write the component expression:\n\n```html\n\u003c!-- ... --\u003e\n    \u003cBasicButton ::$label=\"b.label\" ::$fill=\"b.color\" ::width=\"24\" $$wrap=\"template\" x-for=\"b in buttons\" /\u003e\n\u003c!-- ... --\u003e\n```\n\nTake note of the `$` chars added to the expression properties `label` and `fill`. When Presto compiles, this is what you'll see:\n\n```html\n\u003ctemplate x-for=\"b in buttons\"\u003e\n  \u003cbutton\n    type=\"button\"\n    x-html=\"`${b.label}`\"\n    x-bind:class=\"`py-2 px-4 bg-${b.color}-500 border border-${b.color}-500 hover:bg-${b.color}-400 text-white transition ease-in duration-200 text-center text-base font-semibold rounded-lg w-24`\"\n  \u003e\u003c/button\u003e\n\u003c/template\u003e\n```\n\n#### Take a *very close* look at what's happened:\n\n* The Alpine `x-html` attribute has been added to the `\u003cbutton\u003e` element and will apply the `b.label` value at runtime.\n* The `class` attribute has been converted to `x-bind:class` and its value has been enclosed in backtick `` ` `` template literal chars.\n* Where the `fill` property is expressed in `class`, it's been enclosed as a template literal placeholder `${...}` that will apply the `b.color` value at runtime.\n* Where the `width` property is expressed in `class`, it's been left alone as a string literal.\n\nUsing magic properties, you can take the components you already have or components from existing toolkits (like [TailwindToolbox](https://www.tailwindtoolbox.com)) and, with almost no effort, make them ready for your Alpine-powered frontend while still retaining their usability outside of Alpine's `x-data` scope.\n\n\u003e #### How does this work?\n\u003e \n\u003e Presto is \"context-aware\" — meaning that it can tell when a property is being expressed inside of an element's attribute or inside of its `innerHTML` value. Additionally, it's aware of those attributes which are necessary for Alpine to do its work, like `x-html`, `x-text`, or anything prefixed with `x-bind:`.\n\n### A Little More Magic :sparkles::sparkles:\nSuppose you grab a an icon button from a toolkit and replace its static content with component properties to define `IconButton` like this:\n\n```html\n\u003cmeta presto name=\"IconButton\" ::fill=\"green\" ::icon ::label ::width=\"full\" /\u003e\n\n\u003cbutton\n  type=\"button\"\n  class=\"py-2 px-4 bg-{{ fill }}-500 border border-{{ fill }}-500 hover:bg-{{ fill }}-400 text-white transition ease-in duration-200 text-center text-base font-semibold rounded-lg w-{{ width }}\"\n\u003e\n  \u003ci class=\"fas fa-{{ icon }} mr-1 text-xl\"\u003e\u003c/i\u003e{{ label }}\n\u003c/button\u003e\n```\n\nAt first glance, there doesn't seem to be anything wrong, but within the `innerHTML` of `\u003cbutton\u003e` there's some interesting considerations for Presto:\n\n* A property token, `{{ label }}`, is inline with static HTML.\n* Within that static HTML next to a property token, another property token, `{{ icon }}`, is inside of an attribute.\n\nFor standard Presto expression properties, this is a simple case of substitution, and nothing about which to worry. With Alpine, however, there's more to consider. If you want to dynamically set the property of `label` *and* `icon`, you'd need to wrap `{{ label }}` inside of a `\u003cdiv\u003e` or `\u003cspan\u003e`, so that it can be assigned `x-html`, right?\n\nNot with magic properties! Leaving things as they are, let's write our component expression:\n\n```html\n\u003c!-- ... --\u003e\n    \u003cBasicButton ::$icon=\"b.icon\" ::$label=\"b.label\" ::$fill=\"b.color\" ::width=\"24\" $$wrap=\"template\" x-for=\"b in buttons\" /\u003e\n\u003c!-- ... --\u003e\n```\n\nWhen Presto compiles, *this* is what you'll see:\n\n```html\n\u003ctemplate x-for=\"b in buttons\"\n  \u003e\u003cbutton\n    type=\"button\"\n    x-bind:class=\"`py-2 px-4 bg-${b.color}-500 border border-${b.color}-500 hover:bg-${b.color}-400 text-white transition ease-in duration-200 text-center text-base font-semibold rounded-lg w-24`\"\n    x-html='`\n    \u0026lt;i class\u0026equals;\"fas fa-${b.icon} mr-1 text-xl\"\u0026gt;\u0026lt;/i\u0026gt;${b.label}\n    `'\n  \u003e\u003c/button\u003e\n\u003c/template\u003e\n```\n\n#### Take a close look at what Presto did with `x-html`:\n* Like before, the value is wrapped as a template literal with `` ` `` chars.\n* Where a dynamic expression is required, it's wrapped as a template literal placeholder `${...}`.\n* Most importantly, the entire content of the `innerHTML` of `\u003cbutton\u003e` has been escaped into HTML-safe chars that will render exactly as you require at runtime. Alpine writes each element to the DOM at runtime, and the browser doesn't know any differently.\n\n\u003e #### Just because you can, should you?\n\u003e \n\u003e Probably not.\n\u003e \n\u003e I wrote this feature into Presto because it felt like something that should be there, but when debugging an app, the less complexity there is, the better. If you don't mind taking the extra 1.2 seconds required to wrap your property token inside a `\u003cspan\u003e` element, you may save yourself some time if you ever need to dive into the browser inspector.\n\n## Attribute Coalescence Control\n\nYou've already seen that Presto can coalesce attributes onto the root elements of a component definition. This makes it easy to leverage utility frameworks like Tailwind CSS to create variants of existing components. To even further reduce redundancy, we can extend this behavior using action attributes.\n\n### `$$provides`, `$$reserves`, `$$accepts`, `$$rejects`\n\nAs you begin breaking-down your application's markup into recyclable components, you're likely to find that you have a need to begin nesting fundamental components within others to create variations without redundancy. Consider an input-based example where we have two components, `BasicInput` and `LabeledInput`:\n\n\u003cp align=\"right\"\u003e\u003cstrong\u003e\u003ccode\u003ebasicinput.html\u003c/code\u003e\u003c/strong\u003e\u003c/p\u003e\n\n```html\n\u003cmeta\n  presto\n  name=\"BasicInput\"\n  ::placeholder\n  ::value\n  ::color=\"green\"\n/\u003e\n\n\u003cinput\n  type=\"text\"\n  value=\"{{ value }}\"\n  class=\"rounded-lg border-transparent flex-1 appearance-none border border-gray-300 fw-full py-2 px-4 bg-white text-gray-700 placeholder-gray-400 text-base focus:outline-none focus:border-{{ color }}-400\"\n  placeholder=\"{{ placeholder }}\"\n/\u003e\n```\n\n\u003cp align=\"right\"\u003e\u003cstrong\u003e\u003ccode\u003elabeledinput.html\u003c/code\u003e\u003c/strong\u003e\u003c/p\u003e\n\n```html\n\u003cmeta\n  presto\n  name=\"LabeledInput\"\n  ::label\n  ::placeholder\n  ::value\n  ::color=\"green\"\n/\u003e\n\n\u003cdiv\u003e\n  \u003cdiv class=\"pl-1 text-sm text-gray-700\"\u003e{{ label }}\u003c/div\u003e\n  \u003cBasicInput class=\"w-full\" ::placeholder=\"{{ placeholder }}\" ::value=\"{{ value }}\" ::color=\"{{ color }}\" ::width=\"{{ width }}\" /\u003e\n\u003c/div\u003e\n\n```\n\nThe component definition for `LabeledInput` establishes an expression for `BasicInput`, and explicitly re-declares all of the properties that could be passed onto it. There's nothing wrong with this, and it would indeed work, but it also creates redundancy and requires you to update two component definitions if you decide to change the property declarations on one.\n\nInstead of explicitly re-declaring, you can make use of any combination of Presto action attributes to do the heavy lifting for you, let's rewrite our definition for `LabeledInput`, using the action attributes `$$provides`, `$$reserves`, `$$accepts`, and `$$declared`:\n\n\u003cp align=\"right\"\u003e\u003cstrong\u003e\u003ccode\u003elabeledinput.html\u003c/code\u003e\u003c/strong\u003e\u003c/p\u003e\n\n```html\n\u003cmeta\n  presto\n  name=\"LabeledInput\"\n  ::label\n  $$provides\n  $$reserves=\"$$declared\"\n/\u003e\n\n\u003cdiv\u003e\n  \u003cdiv class=\"pl-1 text-sm text-gray-700\" $$accepts=\"class\"\u003e{{ label }}\u003c/div\u003e\n  \u003cBasicInput class=\"w-full\" $$accepts $$rejects=\"class\" /\u003e\n\u003c/div\u003e\n```\n\nWith our new action attributes in-place, we can now write our component expression for `LabeledInput` as:\n\n```html\n\u003cLabeledInput ::label=\"First Name\" ::placeholder=\"John\" ::$value=\"user.firstName\" /\u003e\n```\n\nLet's break down what each action attribute does for us:\n\n* The `$$provides` attribute, declared with no value, tells Presto that any attributes (property, magic, or plain-old HTML) should not be applied to the markup for `LabeledInput`, but should be held for distribution to elements contained within.\n    * If we wanted to be specific, we could write the value of `$$provides` as `$$provides=\"::placeholder ::value ::color ::width\"`, which would explicitly pass-on only those attributes — retaining the rest for property expression or coalescence.\n* The `$$reserves` attribute, with a value of `$$declared`, tells Presto that while we're passing-on any attribute given on an expression of `LabeledInput`, we still want to keep to value of any declared properties so that they can be expressed in the markup for `LabeledInput`.\n    * Like `$$provides`, giving an empty value for `$$reserves` acts as a wildcard — retaining all attributes given on `LabeledInput` for property expression or coalescence.\n    * The `$$declared` keyword can only be used in the value for `$$reserves` or `$$accepts`. It has no effect in `$$provides`.\n* The `$$accepts` attribute, declared with no value, tells Presto that any attributes collected by `$$provides` should be coalesced onto the expression for `BasicInput`. Again, this works for both properties, magic properties, and plain-old HTML.\n    * Like `$$provides` and `$$reserves`, we can also be explicit in the way that we use `$$accepts`. If desired, we could write `$$accepts=\"::placeholder ::value ::color ::width\"`\n    * Expression of the `$$accepts` attribute can be done multiple times throughout a component definition, and on both component expressions as well as standard HTML elements.\n* The `$$accepts` attribute, declared as `$$accepts=\"class\"` ensure's that any declaration for class on `LabeledInput` is passed on to our wrapping `\u003cdiv\u003e`. In this way, we can express with of our component using Tailwind's `w-XX` classes.\n* The `$$rejects` property, declared as `$$rejects=\"class\"` ensures that we don't pass on the class declarations we intend to use on the wrapping `\u003cdiv\u003e` only.\n\nIn this way, whether you provide an attribute using property syntax, magic syntax, or plain-old HTML, you can tell Presto where you want your declarations to go.\n\n### Implied Coalescence Control: `$$utilizes`\n\nUsing `$$provides` and `$$accepts` is easy enough, but it still exposes us to the potential for added redundancy. Suppose we intend to use `BasicInput` in more than one component. We'd have to write a `$$provides` and `$$accepts` attribute for each occurence — leading to fragmented control.\n\nInstead, where we can anticipate desired attribute coalescence, we can make use of the `$$utilizes` attribute to keep things terse. Let's rewrite the definition for `BasicInput` and assume we have another component, `BasicButton` that we're going to use in a new definition, `OneButtonInput`:\n\n\u003cp align=\"right\"\u003e\u003cstrong\u003e\u003ccode\u003ebasicinput.html\u003c/code\u003e\u003c/strong\u003e\u003c/p\u003e\n\n```html\n\u003cmeta\n  presto\n  name=\"BasicInput\"\n  ::placeholder\n  ::value\n  ::color=\"green\"\n  ::width=\"full\"\n  $$accepts=\"$$declared required readonly\"\n/\u003e\n\n\u003cinput\n  type=\"text\"\n  value=\"{{ value }}\"\n  class=\"rounded-lg border-transparent flex-1 appearance-none border border-gray-300 fw-full py-2 px-4 bg-white text-gray-700 placeholder-gray-400 text-base focus:outline-none focus:border-{{ color }}-400 w-{{ width }}\"\n  placeholder=\"{{ placeholder }}\"\n/\u003e\n```\n\n\u003cp align=\"right\"\u003e\u003cstrong\u003e\u003ccode\u003ebasicbutton.html\u003c/code\u003e\u003c/strong\u003e\u003c/p\u003e\n\n```html\n\u003cmeta\n  presto\n  name=\"BasicButton\"\n  ::click\n  ::label\n  ::color=\"green\"\n  ::text=\"white\"\n  $$accepts=\"$$declared\"\n/\u003e\n\n\u003cbutton\n  type=\"button\"\n  class=\"py-2 px-4 bg-{{ color }}-500 border border-{{ color }}-500 hover:bg-{{ fill }}-400 text-{{ text }} transition ease-in duration-200 text-center text-base font-semibold rounded-lg w-24\"\n  onclick=\"{{ click }}\"\n\u003e\n  {{ label }}\n\u003c/button\u003e\n```\n\nNotice that in both definitions, we've assigned `$$accepts` in the `\u003cmeta\u003e` tag. This indicates to Presto that every expression of our component will acquire provided attributes according to the value for `$$accepts`:\n\n* `BasicInput`\n    * Acquires provided attributes `::placeholder`, `::value`, `::color`, and `::width`, because they are implied by `$$declared`.\n    * Acquires provided attributes `readonly` and `required`, because they are explicitly stated.\n* `BasicButton`\n    * Acquires `::click`, `::label`, `::color`, and `::text` because they are implied by `$$declared`.\n\nLet's write our component definition for `OneButtonInput` with these characteristics in-mind:\n\n\u003cp align=\"right\"\u003e\u003cstrong\u003e\u003ccode\u003eonebuttoninput.html\u003c/code\u003e\u003c/strong\u003e\u003c/p\u003e\n\n```html\n\u003cmeta presto\n  name=\"OneButtonInput\"\n  $$utilizes=\"BasicInput BasicButton\" \n/\u003e\n\n\u003cdiv class=\"flex\"\u003e\n  \u003cBasicInput /\u003e\n  \u003cdiv class=\"flex\"\u003e\n    \u003cBasicButton class=\"mb-auto\" /\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n```\n\nNow, when we write a component expression for `OneButtonInput`, we can express the properties for `BasicInput` and `BasicButton` like this:\n\n```html\n\u003cOneButtonInput required ::placeholder=\"Search...\" ::$value=\"searchTerm\" ::label=\"Go\" ::click=\"performSearch()\" /\u003e\n```\n\nIn the `\u003cmeta\u003e` tag for our component definition, we've established `$$utilizes` and referenced both `BasicButton` and `BasicInput`. This tells Presto to refer to the value of `$$accepts` in each given component definition. Any attributes found there will be treated as if we'd established `$$provides` on `OneButtonInput` and `$$accepts` on each component expression.\n\n### Explicit Coalescence Control: `$$exposes`\n\nLooking at the expression for `OneButtonInput`, we can see that we've left-out a few declared properties and, if we look closely look at the definitions for `BasicButton` and `BasicInput`, we can see that the property `color` is declared in both components with very different implementations. In `BasicButton`, `color` refers to the fill colour of the button, while in `BasicInput`, it refers to the border colour of the input field. If we tried to establish `::color` on `\u003cOneButtonInput\u003e`, Presto would pass on the property to both components, and we may not like what we see.\n\nInstead, we can use the `$$exposes` attribute to designate a prefix controlling attribute coalescence. Consider an example that uses both `BasicInput` and two expressions of `BasicButton`:\n\n\u003cp align=\"right\"\u003e\u003cstrong\u003e\u003ccode\u003etwobuttoninput.html\u003c/code\u003e\u003c/strong\u003e\u003c/p\u003e\n\n```html\n\u003cmeta presto name=\"TwoButtonInput\" $$utilizes=\"BasicInput\"/\u003e\n\n\u003cdiv class=\"flex space-x-2\"\u003e\n  \u003cBasicInput $$exposes=\"input\" /\u003e\n  \u003cBasicButton $$exposes=\"b1\" class=\"mb-auto\" /\u003e\n  \u003cBasicButton $$exposes=\"b2\" class=\"mb-auto\" /\u003e\n\u003c/div\u003e\n```\n\n```html\n\u003cTwoButtonInput\n  required\n  ::$value=\"username\"\n  ::placeholder=\"@johndoe\"\n  input|::color=\"blue\"\n  b1|::click=\"validateUsername()\"\n  b1|::color=\"gray\"\n  b2|::click=\"submitUsername()\"\n  b2|::color=\"blue\"\n/\u003e\n```\n\nOn each instance of `BasicButton` and `BasicInput`, the `$$exposes` attribute provides a moniker through which each individual expression can be addressed. On the component expression for `TwoButtonInput`, this is done by concatenating the value of each `$$exposes` with a pipe `|` char, and then the attribute we want to pass. As we're able to address each element directly, the attributes passed can be properties, magic properties, or plain-old HTML attributes.\n\nWhile it's common that you'll want to pass attributes onto component expressions, you can also use `$$exposes` to expose standard elements as well:\n\n```html\n\u003c!-- In Component Definition --\u003e\n  \u003cdiv $$exposes=\"pangram\" class=\"text-center\"\u003e My faxed joke won a pager in the cable TV quiz show. \u003c/div\u003e\n\n\u003c!-- On Component Expression --\u003e\n  \u003cMyComponent pangram|class=\"font-semibold text-2xl\" /\u003e\n\n\u003c!-- Resulting Markup --\u003e\n  \u003cdiv class=\"text-center font-semibold text-2xl\"\u003e My faxed joke won a pager in the cable TV quiz show. \u003c/div\u003e\n```\n\n### Incremented Exposures: `\u003cmeta presto ... $$exposes \u003e`\n\nIf you prefer a more succinct approach to component exposition, you can also establish the `$$exposes` attribute in the `\u003cmeta\u003e` tag of a component definition:\n\n\u003cp align=\"right\"\u003e\u003cstrong\u003e\u003ccode\u003ebasicbutton.html\u003c/code\u003e\u003c/strong\u003e\u003c/p\u003e\n\n```html\n\u003cmeta\n  presto\n  name=\"BasicButton\"\n  $$exposes=\"button\"\n  ::click\n  ::label\n  ::color=\"green\"\n  ::text=\"white\"\n  $$accepts=\"$$declared\"\n/\u003e\n\u003c!--...--\u003e\n```\n\nNow, when you use `BasicButton` within a component definition, you can access `button|attribute=\"\"` on your expression without providing `$$exposes` directly. If you need multiple occurrences of `BasicButton`, Presto will use numeric incrementation to address each occurrence, starting from the top of your component's markup. In this way, `TwoButtonInput` could be written as:\n\n\u003cp align=\"right\"\u003e\u003cstrong\u003e\u003ccode\u003etwobuttoninput.html\u003c/code\u003e\u003c/strong\u003e\u003c/p\u003e\n\n```html\n\u003cmeta presto name=\"TwoButtonInput\" $$utilizes=\"BasicInput\" /\u003e\n\n\u003cdiv class=\"flex space-x-2\"\u003e\n  \u003cBasicInput /\u003e\n  \u003cBasicButton class=\"mb-auto\" /\u003e\n  \u003cBasicButton class=\"mb-auto\" /\u003e\n\u003c/div\u003e\n```\n\nThen, assuming you also established `$$exposes=\"input\"` in the definition for `BasicInput`, your expression of `TwoButtonInput` could look like this:\n\n```html\n\u003cTwoButtonInput\n  required\n  ::$value=\"username\"\n  ::placeholder=\"@johndoe\"\n  input|::color=\"blue\"\n  button|::click=\"validateUsername()\"\n  button|::color=\"gray\"\n  button2|::click=\"submitUsername()\"\n  button2|::color=\"blue\"\n/\u003e\n```\n\nIndexing for incremented exposure begins at `1`. If you don't provide a numeric value (like the example above), Presto assumes a value of `1` unless another element in the component definition is assigned `$$exposes` directly as `$$exposes=\"button\"`. In cases such as these, Presto would pass anything prefixed with `button|` onto that element, and anything prefixed with `button1|` onto the first instance of `BasicButton`.\n\n### Coalescence Control Reference\n\n#### Declared Only on Component Metadata\n\nAttribute | Function\n:--- | :---\n`$$provides` | Attributes matching this space-delimited list will be distributed to elements or component expressions and not coalesced onto the root component element or expressed as properties.\n`$$reserves` | Attributes matching this space-delimited list will be coalesced onto the root component element or expressed as properties, and not distributed to elements or component expressions.\n`$$utilizes` | The component will implement the `$$provides`, `$$accepts`, `$$reserves`, and `$$exposes` rules of component names matching this space-delimited list.\n`$$declared` (value) | This is a value that can be assigned to `$$reserves` or `$$accepts`, only when expressed on component metadata.\n\n#### Declared on Either Component Metadata or Elements/Component Expressions\n\nAttribute | Function\n:-- | :--\n`$$exposes` | The given value is used as a prefix in the pattern `prefix\\|attribute=\"value\"` to edit the element or component's attributes directly.\n`$$accepts` | Attributes matching this space-delimited list are received for coalescence where given by a `$$provides`declaration.\n\n#### Declared Only on Elements/Component Expresssions\nAttribute | Function — *Must be used with `$$accepts`*\n:--- | :---\n`$$rejects` | Attributes matching this space-delimited list will be rejected for coalescence where given by a `$$provides` declaration *(useful when using wildcard `$$accepts`)*.\n`$$revises` | Attributes matching this space-delimited list will replace (instead of coalesce with) their existing values *(useful for `type` on `\u003cinput type=\"text\" /\u003e`, etc.)*.\n\n\n## License\nCopyright © 2020-2021 Stephan Casas\n\n\nLicensed under the MIT license, see LICENSE for details.\n\n\u003cp\u003e\u003cimg src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==\" width=\"0\" height=\"50\"\u003e\u003c/p\u003e\n\n# About the Project\n\nHi, I'm Stephan, and I'm the developer of Presto.\n\n\u003e #### TL;DR\n\u003e \n\u003e * Presto was built after I got tired of trying to learn Vue and React.\n\u003e * Please be my [friend](https://www.twitter.com/stephancasas).\n\u003e * If you enjoy using Presto, please consider [sponsoring the project](https://github.com/sponsors/stephancasas).\n\nI started work on this project in mid-December and took almost two months off of my primary job as a freelance software developer to bring the concept to life. My work on it began after a single-page report for a client's project ballooned from 50 lines of code to +1200. The report, driven by Alpine, worked flawlessly, but was severely lacking with regards to organization. After taking a phone call in which I tried to debug a discrepancy with the client in realtime, struggling to sift through a mess of `#region` tags and arrowhead comments just wasn't doing it for me. I wanted a better way to work.\n\nThe obvious answer was to switch to React or Vue, but both of them felt like overkill for the use case, and there was the little matter of me not knowing how to use either. After watching several Vue tutorials at [Laracasts](https://www.laracasts.com/), one video's comment stuck with me:\n\n\u003cp align=\"center\"\u003e\u003ci\u003e\u003cstrong\u003e\"This is so much easier to do in Alpine.\"\u003c/strong\u003e\u003c/i\u003e\u003c/p\u003e\n\nThat was the straw that broke the camel's back. He wasn't wrong. Getting up and running with Vue, especially for something as nominal as a single-page report, required a ton of overhead; a steep learning curve; and felt less than intuitive when compared with Alpine. I had everything I needed in my Alpine model — all I wanted was a little organization.\n\nFor about three nights, I scoured the Internet searching for existing solutions. Things came close, but not close enough. The goal I had in-mind was pretty basic: I didn't want to write any JavaScript — *everything had to be HTML-based*. No template literals, no JSX, no pragma... just pure HTML. I didn't find anything.\n\nTo me, it seemed crazy that things like Babel and WebPack existed, but nothing filled-in the transpiler gap for HTML. In reality, though, the need for something like this is a relatively fresh concept. When Caleb Porzio wrote Alpine, he introduced a new way to build reactive frontends that kept developers' work in one place: the DOM. With that in-mind, I got to work. Building something like this seemed like a great way to give back to the open-source community and an opportunity to make new friends. No, seriously, I only know like two other developers — [please be my friend](https://www.twitter.com/stephancasas).\n\nPresto is definitely still in its early stages of development. When I started the project, I wasn't familiar with TypeScript, so there's a considerable amount of refactoring to be done. As I needed Presto to work for my job, lots of \"hacks\" have been applied with `// FIXME:` comments. With a reasonably-working preview, I'll be doing what I can in the coming weeks to burn through these, and promise to open the source up for pull requests once this is completed.\n\nIn the interim, please submit ideas, feedback, bug reports and any other considerations as [issues](https://github.com/stephancasas/presto/issues) right here on GitHub. As with any open-source project, Presto is built as my work allows for it. If you enjoy using Presto, and want to see further development, please consider [sponsoring the project](https://github.com/sponsors/stephancasas).\n\n## Say \"Hello\"\n\n:man_technologist: | **Stephan Casas** \n:---: |:--- \n:email: | stephancasas[at]icloud[dot]com|\n:bird: | [@stephancasas](https://www.twitter.com/stephancasas) |\n:camera: | [@stephancasas](https://www.instagram.com/stephancasas)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstephancasas%2Fpresto","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstephancasas%2Fpresto","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstephancasas%2Fpresto/lists"}