diff --git "a/llms-ctx-fastHtml.txt" "b/llms-ctx-fastHtml.txt"
new file mode 100644--- /dev/null
+++ "b/llms-ctx-fastHtml.txt"
@@ -0,0 +1,3274 @@
+Things to remember when writing FastHTML apps:
+
+- Although parts of its API are inspired by FastAPI, it is *not* compatible with FastAPI syntax and is not targeted at creating API services
+- FastHTML includes support for Pico CSS and the fastlite sqlite library, although using both are optional; sqlalchemy can be used directly or via the fastsql library, and any CSS framework can be used. Support for the Surreal and css-scope-inline libraries are also included, but both are optional
+- FastHTML is compatible with JS-native web components and any vanilla JS library, but not with React, Vue, or Svelte
+- Use `serve()` for running uvicorn (`if __name__ == "__main__"` is not needed since it's automatic)
+- When a title is needed with a response, use `Titled`; note that that already wraps children in `Container`, and already includes both the meta title as well as the H1 element.# Web Devs Quickstart
+
+
+
+## Installation
+
+``` bash
+pip install python-fasthtml
+```
+
+## A Minimal Application
+
+A minimal FastHTML application looks something like this:
+
+
+
+Line 1
+We import what we need for rapid development! A carefully-curated set of
+FastHTML functions and other Python objects is brought into our global
+namespace for convenience.
+
+Line 3
+We instantiate a FastHTML app with the `fast_app()` utility function.
+This provides a number of really useful defaults that we’ll take
+advantage of later in the tutorial.
+
+Line 5
+We use the `rt()` decorator to tell FastHTML what to return when a user
+visits `/` in their browser.
+
+Line 6
+We connect this route to HTTP GET requests by defining a view function
+called `get()`.
+
+Line 7
+A tree of Python function calls that return all the HTML required to
+write a properly formed web page. You’ll soon see the power of this
+approach.
+
+Line 9
+The [`serve()`](https://docs.fastht.ml/api/core.html#serve) utility
+configures and runs FastHTML using a library called `uvicorn`.
+
+Run the code:
+
+``` bash
+python main.py
+```
+
+The terminal will look like this:
+
+``` bash
+INFO: Uvicorn running on http://0.0.0.0:5001 (Press CTRL+C to quit)
+INFO: Started reloader process [58058] using WatchFiles
+INFO: Started server process [58060]
+INFO: Waiting for application startup.
+INFO: Application startup complete.
+```
+
+Confirm FastHTML is running by opening your web browser to
+[127.0.0.1:5001](http://127.0.0.1:5001). You should see something like
+the image below:
+
+
+
+
+
+> **Note**
+>
+> While some linters and developers will complain about the wildcard
+> import, it is by design here and perfectly safe. FastHTML is very
+> deliberate about the objects it exports in `fasthtml.common`. If it
+> bothers you, you can import the objects you need individually, though
+> it will make the code more verbose and less readable.
+>
+> If you want to learn more about how FastHTML handles imports, we cover
+> that [here](https://docs.fastht.ml/explains/faq.html#why-use-import).
+
+
+
+## A Minimal Charting Application
+
+The [`Script`](https://docs.fastht.ml/api/xtend.html#script) function
+allows you to include JavaScript. You can use Python to generate parts
+of your JS or JSON like this:
+
+``` python
+import json
+from fasthtml.common import *
+
+app, rt = fast_app(hdrs=(Script(src="https://cdn.plot.ly/plotly-2.32.0.min.js"),))
+
+data = json.dumps({
+ "data": [{"x": [1, 2, 3, 4],"type": "scatter"},
+ {"x": [1, 2, 3, 4],"y": [16, 5, 11, 9],"type": "scatter"}],
+ "title": "Plotly chart in FastHTML ",
+ "description": "This is a demo dashboard",
+ "type": "scatter"
+})
+
+
+@rt("/")
+def get():
+ return Titled("Chart Demo", Div(id="myDiv"),
+ Script(f"var data = {data}; Plotly.newPlot('myDiv', data);"))
+
+serve()
+```
+
+## Debug Mode
+
+When we can’t figure out a bug in FastHTML, we can run it in `DEBUG`
+mode. When an error is thrown, the error screen is displayed in the
+browser. This error setting should never be used in a deployed app.
+
+``` python
+from fasthtml.common import *
+
+app, rt = fast_app(debug=True)
+
+@rt("/")
+def get():
+ 1/0
+ return Titled("FastHTML Error!", P("Let's error!"))
+
+serve()
+```
+
+Line 3
+`debug=True` sets debug mode on.
+
+Line 7
+Python throws an error when it tries to divide an integer by zero.
+
+## Routing
+
+FastHTML builds upon FastAPI’s friendly decorator pattern for specifying
+URLs, with extra features:
+
+
+
+Line 5
+The “/” URL on line 5 is the home of a project. This would be accessed
+at [127.0.0.1:5001](http://127.0.0.1:5001).
+
+Line 9
+“/hello” URL on line 9 will be found by the project if the user visits
+[127.0.0.1:5001/hello](http://127.0.0.1:5001/hello).
+
+
+
+> **Tip**
+>
+> It looks like `get()` is being defined twice, but that’s not the case.
+> Each function decorated with `rt` is totally separate, and is injected
+> into the router. We’re not calling them in the module’s namespace
+> (`locals()`). Rather, we’re loading them into the routing mechanism
+> using the `rt` decorator.
+
+
+
+You can do more! Read on to learn what we can do to make parts of the
+URL dynamic.
+
+## Variables in URLs
+
+You can add variable sections to a URL by marking them with
+`{variable_name}`. Your function then receives the `{variable_name}` as
+a keyword argument, but only if it is the correct type. Here’s an
+example:
+
+
+
+Line 5
+We specify two variable names, `name` and `age`.
+
+Line 6
+We define two function arguments named identically to the variables. You
+will note that we specify the Python types to be passed.
+
+Line 7
+We use these functions in our project.
+
+Try it out by going to this address:
+[127.0.0.1:5001/uma/5](http://127.0.0.1:5001/uma/5). You should get a
+page that says,
+
+> “Hello Uma, age 5”.
+
+### What happens if we enter incorrect data?
+
+The [127.0.0.1:5001/uma/5](http://127.0.0.1:5001/uma/5) URL works
+because `5` is an integer. If we enter something that is not, such as
+[127.0.0.1:5001/uma/five](http://127.0.0.1:5001/uma/five), then FastHTML
+will return an error instead of a web page.
+
+
+
+> **FastHTML URL routing supports more complex types**
+>
+> The two examples we provide here use Python’s built-in `str` and `int`
+> types, but you can use your own types, including more complex ones
+> such as those defined by libraries like
+> [attrs](https://pypi.org/project/attrs/),
+> [pydantic](https://pypi.org/project/pydantic/), and even
+> [sqlmodel](https://pypi.org/project/sqlmodel/).
+
+
+
+## HTTP Methods
+
+FastHTML matches function names to HTTP methods. So far the URL routes
+we’ve defined have been for HTTP GET methods, the most common method for
+web pages.
+
+Form submissions often are sent as HTTP POST. When dealing with more
+dynamic web page designs, also known as Single Page Apps (SPA for
+short), the need can arise for other methods such as HTTP PUT and HTTP
+DELETE. The way FastHTML handles this is by changing the function name.
+
+
+
+Line 6
+On line 6 because the `get()` function name is used, this will handle
+HTTP GETs going to the `/` URI.
+
+Line 10
+On line 10 because the `post()` function name is used, this will handle
+HTTP POSTs going to the `/` URI.
+
+## CSS Files and Inline Styles
+
+Here we modify default headers to demonstrate how to use the [Sakura CSS
+microframework](https://github.com/oxalorg/sakura) instead of FastHTML’s
+default of Pico CSS.
+
+
+
+Line 4
+By setting `pico` to `False`, FastHTML will not include `pico.min.css`.
+
+Line 7
+This will generate an HTML `` tag for sourcing the css for Sakura.
+
+Line 8
+If you want an inline styles, the
+[`Style()`](https://docs.fastht.ml/api/xtend.html#style) function will
+put the result into the HTML.
+
+## Other Static Media File Locations
+
+As you saw, [`Script`](https://docs.fastht.ml/api/xtend.html#script) and
+`Link` are specific to the most common static media use cases in web
+apps: including JavaScript, CSS, and images. But it also works with
+videos and other static media files. The default behavior is to look for
+these files in the root directory - typically we don’t do anything
+special to include them. We can change the default directory that is
+looked in for files by adding the `static_path` parameter to the
+`fast_app` function.
+
+``` python
+app, rt = fast_app(static_path='public')
+```
+
+FastHTML also allows us to define a route that uses `FileResponse` to
+serve the file at a specified path. This is useful for serving images,
+videos, and other media files from a different directory without having
+to change the paths of many files. So if we move the directory
+containing the media files, we only need to change the path in one
+place. In the example below, we call images from a directory called
+`public`.
+
+``` python
+@rt("/{fname:path}.{ext:static}")
+async def get(fname:str, ext:str):
+ return FileResponse(f'public/{fname}.{ext}')
+```
+
+## Rendering Markdown
+
+``` python
+from fasthtml.common import *
+
+hdrs = (MarkdownJS(), HighlightJS(langs=['python', 'javascript', 'html', 'css']), )
+
+app, rt = fast_app(hdrs=hdrs)
+
+content = """
+Here are some _markdown_ elements.
+
+- This is a list item
+- This is another list item
+- And this is a third list item
+
+**Fenced code blocks work here.**
+"""
+
+@rt('/')
+def get(req):
+ return Titled("Markdown rendering example", Div(content,cls="marked"))
+
+serve()
+```
+
+## Code highlighting
+
+Here’s how to highlight code without any markdown configuration.
+
+``` python
+from fasthtml.common import *
+
+# Add the HighlightJS built-in header
+hdrs = (HighlightJS(langs=['python', 'javascript', 'html', 'css']),)
+
+app, rt = fast_app(hdrs=hdrs)
+
+code_example = """
+import datetime
+import time
+
+for i in range(10):
+ print(f"{datetime.datetime.now()}")
+ time.sleep(1)
+"""
+
+@rt('/')
+def get(req):
+ return Titled("Markdown rendering example",
+ Div(
+ # The code example needs to be surrounded by
+ # Pre & Code elements
+ Pre(Code(code_example))
+ ))
+
+serve()
+```
+
+## Defining new `ft` components
+
+We can build our own `ft` components and combine them with other
+components. The simplest method is defining them as a function.
+
+``` python
+from fasthtml.common import *
+```
+
+``` python
+def hero(title, statement):
+ return Div(H1(title),P(statement), cls="hero")
+
+# usage example
+Main(
+ hero("Hello World", "This is a hero statement")
+)
+```
+
+``` html
+
+
Hello World
+
This is a hero statement
+
+
+```
+
+### Pass through components
+
+For when we need to define a new component that allows zero-to-many
+components to be nested within them, we lean on Python’s `*args` and
+`**kwargs` mechanism. Useful for creating page layout controls.
+
+``` python
+def layout(*args, **kwargs):
+ """Dashboard layout for all our dashboard views"""
+ return Main(
+ H1("Dashboard"),
+ Div(*args, **kwargs),
+ cls="dashboard",
+ )
+
+# usage example
+layout(
+ Ul(*[Li(o) for o in range(3)]),
+ P("Some content", cls="description"),
+)
+```
+
+``` html
+
Dashboard
+
+
+
0
+
1
+
2
+
+
Some content
+
+
+```
+
+### Dataclasses as ft components
+
+While functions are easy to read, for more complex components some might
+find it easier to use a dataclass.
+
+``` python
+from dataclasses import dataclass
+
+@dataclass
+class Hero:
+ title: str
+ statement: str
+
+ def __ft__(self):
+ """ The __ft__ method renders the dataclass at runtime."""
+ return Div(H1(self.title),P(self.statement), cls="hero")
+
+# usage example
+Main(
+ Hero("Hello World", "This is a hero statement")
+)
+```
+
+``` html
+
+
Hello World
+
This is a hero statement
+
+
+```
+
+## Testing views in notebooks
+
+Because of the ASGI event loop it is currently impossible to run
+FastHTML inside a notebook. However, we can still test the output of our
+views. To do this, we leverage Starlette, an ASGI toolkit that FastHTML
+uses.
+
+``` python
+# First we instantiate our app, in this case we remove the
+# default headers to reduce the size of the output.
+app, rt = fast_app(default_hdrs=False)
+
+# Setting up the Starlette test client
+from starlette.testclient import TestClient
+client = TestClient(app)
+
+# Usage example
+@rt("/")
+def get():
+ return Titled("FastHTML is awesome",
+ P("The fastest way to create web apps in Python"))
+
+print(client.get("/").text)
+```
+
+
+
+
+ FastHTML is awesome
+
+
FastHTML is awesome
+
The fastest way to create web apps in Python
+
+
+
+## Forms
+
+To validate data coming from users, first define a dataclass
+representing the data you want to check. Here’s an example representing
+a signup form.
+
+``` python
+from dataclasses import dataclass
+
+@dataclass
+class Profile: email:str; phone:str; age:int
+```
+
+Create an FT component representing an empty version of that form. Don’t
+pass in any value to fill the form, that gets handled later.
+
+``` python
+profile_form = Form(method="post", action="/profile")(
+ Fieldset(
+ Label('Email', Input(name="email")),
+ Label("Phone", Input(name="phone")),
+ Label("Age", Input(name="age")),
+ ),
+ Button("Save", type="submit"),
+ )
+profile_form
+```
+
+``` html
+
+```
+
+Once the dataclass and form function are completed, we can add data to
+the form. To do that, instantiate the profile dataclass:
+
+``` python
+profile = Profile(email='john@example.com', phone='123456789', age=5)
+profile
+```
+
+ Profile(email='john@example.com', phone='123456789', age=5)
+
+Then add that data to the `profile_form` using FastHTML’s
+[`fill_form`](https://docs.fastht.ml/api/components.html#fill_form)
+class:
+
+``` python
+fill_form(profile_form, profile)
+```
+
+``` html
+
+```
+
+### Forms with views
+
+The usefulness of FastHTML forms becomes more apparent when they are
+combined with FastHTML views. We’ll show how this works by using the
+test client from above. First, let’s create a SQlite database:
+
+``` python
+db = database("profiles.db")
+profiles = db.create(Profile, pk="email")
+```
+
+Now we insert a record into the database:
+
+``` python
+profiles.insert(profile)
+```
+
+ Profile(email='john@example.com', phone='123456789', age=5)
+
+And we can then demonstrate in the code that form is filled and
+displayed to the user.
+
+``` python
+@rt("/profile/{email}")
+def profile(email:str):
+ profile = profiles[email]
+ filled_profile_form = fill_form(profile_form, profile)
+ return Titled(f'Profile for {profile.email}', filled_profile_form)
+
+print(client.get(f"/profile/john@example.com").text)
+```
+
+Line 3
+Fetch the profile using the profile table’s `email` primary key
+
+Line 4
+Fill the form for display.
+
+
+
+
+
+ Profile for john@example.com
+
+
Profile for john@example.com
+
+
+
+And now let’s demonstrate making a change to the data.
+
+``` python
+@rt("/profile")
+def post(profile: Profile):
+ profiles.update(profile)
+ return RedirectResponse(url=f"/profile/{profile.email}")
+
+new_data = dict(email='john@example.com', phone='7654321', age=25)
+print(client.post("/profile", data=new_data).text)
+```
+
+Line 2
+We use the `Profile` dataclass definition to set the type for the
+incoming `profile` content. This validates the field types for the
+incoming data
+
+Line 3
+Taking our validated data, we updated the profiles table
+
+Line 4
+We redirect the user back to their profile view
+
+Line 7
+The display is of the profile form view showing the changes in data.
+
+
+
+
+
+ Profile for john@example.com
+
+
Profile for john@example.com
+
+
+
+## Strings and conversion order
+
+The general rules for rendering are: - `__ft__` method will be called
+(for default components like `P`, `H2`, etc. or if you define your own
+components) - If you pass a string, it will be escaped - On other python
+objects, `str()` will be called
+
+As a consequence, if you want to include plain HTML tags directly into
+e.g. a `Div()` they will get escaped by default (as a security measure
+to avoid code injections). This can be avoided by using `NotStr()`, a
+convenient way to reuse python code that returns already HTML. If you
+use pandas, you can use `pandas.DataFrame.to_html()` to get a nice
+table. To include the output a FastHTML, wrap it in `NotStr()`, like
+`Div(NotStr(df.to_html()))`.
+
+Above we saw how a dataclass behaves with the `__ft__` method defined.
+On a plain dataclass, `str()` will be called (but not escaped).
+
+``` python
+from dataclasses import dataclass
+
+@dataclass
+class Hero:
+ title: str
+ statement: str
+
+# rendering the dataclass with the default method
+Main(
+ Hero("
Hello World
", "This is a hero statement")
+)
+```
+
+``` html
+Hero(title='
Hello World
', statement='This is a hero statement')
+```
+
+``` python
+# This will display the HTML as text on your page
+Div("Let's include some HTML here:
Some HTML
")
+```
+
+``` html
+
Let's include some HTML here: <div>Some HTML</div>
+```
+
+``` python
+# Keep the string untouched, will be rendered on the page
+Div(NotStr("
Some HTML
"))
+```
+
+``` html
+
Some HTML
+```
+
+## Custom exception handlers
+
+FastHTML allows customization of exception handlers, but does so
+gracefully. What this means is by default it includes all the ``
+tags needed to display attractive content. Try it out!
+
+``` python
+from fasthtml.common import *
+
+def not_found(req, exc): return Titled("404: I don't exist!")
+
+exception_handlers = {404: not_found}
+
+app, rt = fast_app(exception_handlers=exception_handlers)
+
+@rt('/')
+def get():
+ return (Titled("Home page", P(A(href="/oops")("Click to generate 404 error"))))
+
+serve()
+```
+
+We can also use lambda to make things more terse:
+
+``` python
+from fasthtml.common import *
+
+exception_handlers={
+ 404: lambda req, exc: Titled("404: I don't exist!"),
+ 418: lambda req, exc: Titled("418: I'm a teapot!")
+}
+
+app, rt = fast_app(exception_handlers=exception_handlers)
+
+@rt('/')
+def get():
+ return (Titled("Home page", P(A(href="/oops")("Click to generate 404 error"))))
+
+serve()
+```
+
+## Cookies
+
+We can set cookies using the
+[`cookie()`](https://docs.fastht.ml/api/core.html#cookie) function. In
+our example, we’ll create a `timestamp` cookie.
+
+``` python
+from datetime import datetime
+from IPython.display import HTML
+```
+
+``` python
+@rt("/settimestamp")
+def get(req):
+ now = datetime.now()
+ return P(f'Set to {now}'), cookie('now', datetime.now())
+
+HTML(client.get('/settimestamp').text)
+```
+
+
+
+
+FastHTML page
+
+
Set to 2024-09-26 15:33:48.141869
+
+
+
+Now let’s get it back using the same name for our parameter as the
+cookie name.
+
+``` python
+@rt('/gettimestamp')
+def get(now:parsed_date): return f'Cookie was set at time {now.time()}'
+
+client.get('/gettimestamp').text
+```
+
+ 'Cookie was set at time 15:33:48.141903'
+
+## Sessions
+
+For convenience and security, FastHTML has a mechanism for storing small
+amounts of data in the user’s browser. We can do this by adding a
+`session` argument to routes. FastHTML sessions are Python dictionaries,
+and we can leverage to our benefit. The example below shows how to
+concisely set and get sessions.
+
+``` python
+@rt('/adder/{num}')
+def get(session, num: int):
+ session.setdefault('sum', 0)
+ session['sum'] = session.get('sum') + num
+ return Response(f'The sum is {session["sum"]}.')
+```
+
+## Toasts (also known as Messages)
+
+Toasts, sometimes called “Messages” are small notifications usually in
+colored boxes used to notify users that something has happened. Toasts
+can be of four types:
+
+- info
+- success
+- warning
+- error
+
+Examples toasts might include:
+
+- “Payment accepted”
+- “Data submitted”
+- “Request approved”
+
+Toasts require the use of the `setup_toasts()` function plus every view
+needs these two features:
+
+- The session argument
+- Must return FT components
+
+``` python
+setup_toasts(app)
+
+@rt('/toasting')
+def get(session):
+ # Normally one toast is enough, this allows us to see
+ # different toast types in action.
+ add_toast(session, f"Toast is being cooked", "info")
+ add_toast(session, f"Toast is ready", "success")
+ add_toast(session, f"Toast is getting a bit crispy", "warning")
+ add_toast(session, f"Toast is burning!", "error")
+ return Titled("I like toast")
+```
+
+Line 1
+`setup_toasts` is a helper function that adds toast dependencies.
+Usually this would be declared right after `fast_app()`
+
+Line 4
+Toasts require sessions
+
+Line 11
+Views with Toasts must return FT or FtResponse components.
+
+💡 `setup_toasts` takes a `duration` input that allows you to specify
+how long a toast will be visible before disappearing. For example
+`setup_toasts(duration=5)` sets the toasts duration to 5 seconds. By
+default toasts disappear after 10 seconds.
+
+## Authentication and authorization
+
+In FastHTML the tasks of authentication and authorization are handled
+with Beforeware. Beforeware are functions that run before the route
+handler is called. They are useful for global tasks like ensuring users
+are authenticated or have permissions to access a view.
+
+First, we write a function that accepts a request and session arguments:
+
+``` python
+# Status code 303 is a redirect that can change POST to GET,
+# so it's appropriate for a login page.
+login_redir = RedirectResponse('/login', status_code=303)
+
+def user_auth_before(req, sess):
+ # The `auth` key in the request scope is automatically provided
+ # to any handler which requests it, and can not be injected
+ # by the user using query params, cookies, etc, so it should
+ # be secure to use.
+ auth = req.scope['auth'] = sess.get('auth', None)
+ # If the session key is not there, it redirects to the login page.
+ if not auth: return login_redir
+```
+
+Now we pass our `user_auth_before` function as the first argument into a
+[`Beforeware`](https://docs.fastht.ml/api/core.html#beforeware) class.
+We also pass a list of regular expressions to the `skip` argument,
+designed to allow users to still get to the home and login pages.
+
+``` python
+beforeware = Beforeware(
+ user_auth_before,
+ skip=[r'/favicon\.ico', r'/static/.*', r'.*\.css', r'.*\.js', '/login', '/']
+)
+
+app, rt = fast_app(before=beforeware)
+```
+
+## Server-sent events (SSE)
+
+With [server-sent
+events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events),
+it’s possible for a server to send new data to a web page at any time,
+by pushing messages to the web page. Unlike WebSockets, SSE can only go
+in one direction: server to client. SSE is also part of the HTTP
+specification unlike WebSockets which uses its own specification.
+
+FastHTML introduces several tools for working with SSE which are covered
+in the example below. While concise, there’s a lot going on in this
+function so we’ve annotated it quite a bit.
+
+``` python
+import random
+from asyncio import sleep
+from fasthtml.common import *
+
+hdrs=(Script(src="https://unpkg.com/htmx-ext-sse@2.2.1/sse.js"),)
+app,rt = fast_app(hdrs=hdrs)
+
+@rt
+def index():
+ return Titled("SSE Random Number Generator",
+ P("Generate pairs of random numbers, as the list grows scroll downwards."),
+ Div(hx_ext="sse",
+ sse_connect="/number-stream",
+ hx_swap="beforeend show:bottom",
+ sse_swap="message"))
+
+shutdown_event = signal_shutdown()
+
+async def number_generator():
+ while not shutdown_event.is_set():
+ data = Article(random.randint(1, 100))
+ yield sse_message(data)
+ await sleep(1)
+
+@rt("/number-stream")
+async def get(): return EventStream(number_generator())
+```
+
+Line 5
+Import the HTMX SSE extension
+
+Line 12
+Tell HTMX to load the SSE extension
+
+Line 13
+Look at the `/number-stream` endpoint for SSE content
+
+Line 14
+When new items come in from the SSE endpoint, add them at the end of the
+current content within the div. If they go beyond the screen, scroll
+downwards
+
+Line 15
+Specify the name of the event. FastHTML’s default event name is
+“message”. Only change if you have more than one call to SSE endpoints
+within a view
+
+Line 17
+Set up the asyncio event loop
+
+Line 19
+Don’t forget to make this an `async` function!
+
+Line 20
+Iterate through the asyncio event loop
+
+Line 22
+We yield the data. Data ideally should be comprised of FT components as
+that plugs nicely into HTMX in the browser
+
+Line 26
+The endpoint view needs to be an async function that returns a
+[`EventStream`](https://docs.fastht.ml/api/core.html#eventstream)
+
+## Websockets
+
+With websockets we can have bi-directional communications between a
+browser and client. Websockets are useful for things like chat and
+certain types of games. While websockets can be used for single
+direction messages from the server (i.e. telling users that a process is
+finished), that task is arguably better suited for SSE.
+
+FastHTML provides useful tools for adding websockets to your pages.
+
+``` python
+from fasthtml.common import *
+from asyncio import sleep
+
+app, rt = fast_app(exts='ws')
+
+def mk_inp(): return Input(id='msg', autofocus=True)
+
+@rt('/')
+async def get(request):
+ cts = Div(
+ Div(id='notifications'),
+ Form(mk_inp(), id='form', ws_send=True),
+ hx_ext='ws', ws_connect='/ws')
+ return Titled('Websocket Test', cts)
+
+async def on_connect(send):
+ print('Connected!')
+ await send(Div('Hello, you have connected', id="notifications"))
+
+async def on_disconnect(ws):
+ print('Disconnected!')
+
+@app.ws('/ws', conn=on_connect, disconn=on_disconnect)
+async def ws(msg:str, send):
+ await send(Div('Hello ' + msg, id="notifications"))
+ await sleep(2)
+ return Div('Goodbye ' + msg, id="notifications"), mk_inp()
+```
+
+Line 4
+To use websockets in FastHTML, you must instantiate the app with `exts`
+set to ‘ws’
+
+Line 6
+As we want to use websockets to reset the form, we define the `mk_input`
+function that can be called from multiple locations
+
+Line 12
+We create the form and mark it with the `ws_send` attribute, which is
+documented here in the [HTMX websocket
+specification](https://v1.htmx.org/extensions/web-sockets/). This tells
+HTMX to send a message to the nearest websocket based on the trigger for
+the form element, which for forms is pressing the `enter` key, an action
+considered to be a form submission
+
+Line 13
+This is where the HTMX extension is loaded (`hx_ext='ws'`) and the
+nearest websocket is defined (`ws_connect='/ws'`)
+
+Line 16
+When a websocket first connects we can optionally have it call a
+function that accepts a `send` argument. The `send` argument will push a
+message to the browser.
+
+Line 18
+Here we use the `send` function that was passed into the `on_connect`
+function to send a `Div` with an `id` of `notifications` that HTMX
+assigns to the element in the page that already has an `id` of
+`notifications`
+
+Line 20
+When a websocket disconnects we can call a function which takes no
+arguments. Typically the role of this function is to notify the server
+to take an action. In this case, we print a simple message to the
+console
+
+Line 23
+We use the `app.ws` decorator to mark that `/ws` is the route for our
+websocket. We also pass in the two optional `conn` and `disconn`
+parameters to this decorator. As a fun experiment, remove the `conn` and
+`disconn` arguments and see what happens
+
+Line 24
+Define the `ws` function as async. This is necessary for ASGI to be able
+to serve websockets. The function accepts two arguments, a `msg` that is
+user input from the browser, and a `send` function for pushing data back
+to the browser
+
+Line 25
+The `send` function is used here to send HTML back to the page. As the
+HTML has an `id` of `notifications`, HTMX will overwrite what is already
+on the page with the same ID
+
+Line 27
+The websocket function can also be used to return a value. In this case,
+it is a tuple of two HTML elements. HTMX will take the elements and
+replace them where appropriate. As both have `id` specified
+(`notifications` and `msg` respectively), they will replace their
+predecessor on the page.
+
+## File Uploads
+
+A common task in web development is uploading files. The examples below
+are for uploading files to the hosting server, with information about
+the uploaded file presented to the user.
+
+
+
+> **File uploads in production can be dangerous**
+>
+> File uploads can be the target of abuse, accidental or intentional.
+> That means users may attempt to upload files that are too large or
+> present a security risk. This is especially of concern for public
+> facing apps. File upload security is outside the scope of this
+> tutorial, for now we suggest reading the [OWASP File Upload Cheat
+> Sheet](https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html).
+
+
+
+### Single File Uploads
+
+``` python
+from fasthtml.common import *
+from pathlib import Path
+
+app, rt = fast_app()
+
+upload_dir = Path("filez")
+upload_dir.mkdir(exist_ok=True)
+
+@rt('/')
+def get():
+ return Titled("File Upload Demo",
+ Article(
+ Form(hx_post=upload, hx_target="#result-one")(
+ Input(type="file", name="file"),
+ Button("Upload", type="submit", cls='secondary'),
+ ),
+ Div(id="result-one")
+ )
+ )
+
+def FileMetaDataCard(file):
+ return Article(
+ Header(H3(file.filename)),
+ Ul(
+ Li('Size: ', file.size),
+ Li('Content Type: ', file.content_type),
+ Li('Headers: ', file.headers),
+ )
+ )
+
+@rt
+async def upload(file: UploadFile):
+ card = FileMetaDataCard(file)
+ filebuffer = await file.read()
+ (upload_dir / file.filename).write_bytes(filebuffer)
+ return card
+
+serve()
+```
+
+Line 13
+Every form rendered with the
+[`Form`](https://docs.fastht.ml/api/xtend.html#form) FT component
+defaults to `enctype="multipart/form-data"`
+
+Line 14
+Don’t forget to set the `Input` FT Component’s type to `file`
+
+Line 32
+The upload view should receive a [Starlette
+UploadFile](https://www.starlette.io/requests/#request-files) type. You
+can add other form variables
+
+Line 33
+We can access the metadata of the card (filename, size, content_type,
+headers), a quick and safe process. We set that to the card variable
+
+Line 34
+In order to access the contents contained within a file we use the
+`await` method to read() it. As files may be quite large or contain bad
+data, this is a seperate step from accessing metadata
+
+Line 35
+This step shows how to use Python’s built-in `pathlib.Path` library to
+write the file to disk.
+
+### Multiple File Uploads
+
+``` python
+from fasthtml.common import *
+from pathlib import Path
+
+app, rt = fast_app()
+
+upload_dir = Path("filez")
+upload_dir.mkdir(exist_ok=True)
+
+@rt('/')
+def get():
+ return Titled("Multiple File Upload Demo",
+ Article(
+ Form(hx_post=upload_many, hx_target="#result-many")(
+ Input(type="file", name="files", multiple=True),
+ Button("Upload", type="submit", cls='secondary'),
+ ),
+ Div(id="result-many")
+ )
+ )
+
+def FileMetaDataCard(file):
+ return Article(
+ Header(H3(file.filename)),
+ Ul(
+ Li('Size: ', file.size),
+ Li('Content Type: ', file.content_type),
+ Li('Headers: ', file.headers),
+ )
+ )
+
+@rt
+async def upload_many(files: list[UploadFile]):
+ cards = []
+ for file in files:
+ cards.append(FileMetaDataCard(file))
+ filebuffer = await file.read()
+ (upload_dir / file.filename).write_bytes(filebuffer)
+ return cards
+
+serve()
+```
+
+Line 13
+Every form rendered with the
+[`Form`](https://docs.fastht.ml/api/xtend.html#form) FT component
+defaults to `enctype="multipart/form-data"`
+
+Line 14
+Don’t forget to set the `Input` FT Component’s type to `file` and assign
+the multiple attribute to `True`
+
+Line 32
+The upload view should receive a `list` containing the [Starlette
+UploadFile](https://www.starlette.io/requests/#request-files) type. You
+can add other form variables
+
+Line 34
+Iterate through the files
+
+Line 35
+We can access the metadata of the card (filename, size, content_type,
+headers), a quick and safe process. We add that to the cards variable
+
+Line 36
+In order to access the contents contained within a file we use the
+`await` method to read() it. As files may be quite large or contain bad
+data, this is a seperate step from accessing metadata
+
+Line 37
+This step shows how to use Python’s built-in `pathlib.Path` library to
+write the file to disk.+++
+title = "Reference"
++++
+
+## Contents
+
+* [htmx Core Attributes](#attributes)
+* [htmx Additional Attributes](#attributes-additional)
+* [htmx CSS Classes](#classes)
+* [htmx Request Headers](#request_headers)
+* [htmx Response Headers](#response_headers)
+* [htmx Events](#events)
+* [htmx Extensions](/extensions)
+* [JavaScript API](#api)
+* [Configuration Options](#config)
+
+## Core Attribute Reference {#attributes}
+
+The most common attributes when using htmx.
+
+
+
+| Attribute | Description |
+|--------------------------------------------------|--------------------------------------------------------------------------------------------------------------------|
+| [`hx-get`](@/attributes/hx-get.md) | issues a `GET` to the specified URL |
+| [`hx-post`](@/attributes/hx-post.md) | issues a `POST` to the specified URL |
+| [`hx-on*`](@/attributes/hx-on.md) | handle events with inline scripts on elements |
+| [`hx-push-url`](@/attributes/hx-push-url.md) | push a URL into the browser location bar to create history |
+| [`hx-select`](@/attributes/hx-select.md) | select content to swap in from a response |
+| [`hx-select-oob`](@/attributes/hx-select-oob.md) | select content to swap in from a response, somewhere other than the target (out of band) |
+| [`hx-swap`](@/attributes/hx-swap.md) | controls how content will swap in (`outerHTML`, `beforeend`, `afterend`, ...) |
+| [`hx-swap-oob`](@/attributes/hx-swap-oob.md) | mark element to swap in from a response (out of band) |
+| [`hx-target`](@/attributes/hx-target.md) | specifies the target element to be swapped |
+| [`hx-trigger`](@/attributes/hx-trigger.md) | specifies the event that triggers the request |
+| [`hx-vals`](@/attributes/hx-vals.md) | add values to submit with the request (JSON format) |
+
+
+
+## Additional Attribute Reference {#attributes-additional}
+
+All other attributes available in htmx.
+
+
+
+| Attribute | Description |
+|------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------|
+| [`hx-boost`](@/attributes/hx-boost.md) | add [progressive enhancement](https://en.wikipedia.org/wiki/Progressive_enhancement) for links and forms |
+| [`hx-confirm`](@/attributes/hx-confirm.md) | shows a `confirm()` dialog before issuing a request |
+| [`hx-delete`](@/attributes/hx-delete.md) | issues a `DELETE` to the specified URL |
+| [`hx-disable`](@/attributes/hx-disable.md) | disables htmx processing for the given node and any children nodes |
+| [`hx-disabled-elt`](@/attributes/hx-disabled-elt.md) | adds the `disabled` attribute to the specified elements while a request is in flight |
+| [`hx-disinherit`](@/attributes/hx-disinherit.md) | control and disable automatic attribute inheritance for child nodes |
+| [`hx-encoding`](@/attributes/hx-encoding.md) | changes the request encoding type |
+| [`hx-ext`](@/attributes/hx-ext.md) | extensions to use for this element |
+| [`hx-headers`](@/attributes/hx-headers.md) | adds to the headers that will be submitted with the request |
+| [`hx-history`](@/attributes/hx-history.md) | prevent sensitive data being saved to the history cache |
+| [`hx-history-elt`](@/attributes/hx-history-elt.md) | the element to snapshot and restore during history navigation |
+| [`hx-include`](@/attributes/hx-include.md) | include additional data in requests |
+| [`hx-indicator`](@/attributes/hx-indicator.md) | the element to put the `htmx-request` class on during the request |
+| [`hx-inherit`](@/attributes/hx-inherit.md) | control and enable automatic attribute inheritance for child nodes if it has been disabled by default |
+| [`hx-params`](@/attributes/hx-params.md) | filters the parameters that will be submitted with a request |
+| [`hx-patch`](@/attributes/hx-patch.md) | issues a `PATCH` to the specified URL |
+| [`hx-preserve`](@/attributes/hx-preserve.md) | specifies elements to keep unchanged between requests |
+| [`hx-prompt`](@/attributes/hx-prompt.md) | shows a `prompt()` before submitting a request |
+| [`hx-put`](@/attributes/hx-put.md) | issues a `PUT` to the specified URL |
+| [`hx-replace-url`](@/attributes/hx-replace-url.md) | replace the URL in the browser location bar |
+| [`hx-request`](@/attributes/hx-request.md) | configures various aspects of the request |
+| [`hx-sync`](@/attributes/hx-sync.md) | control how requests made by different elements are synchronized |
+| [`hx-validate`](@/attributes/hx-validate.md) | force elements to validate themselves before a request |
+| [`hx-vars`](@/attributes/hx-vars.md) | adds values dynamically to the parameters to submit with the request (deprecated, please use [`hx-vals`](@/attributes/hx-vals.md)) |
+
+
+
+## CSS Class Reference {#classes}
+
+
+
+| Class | Description |
+|-----------|-------------|
+| `htmx-added` | Applied to a new piece of content before it is swapped, removed after it is settled.
+| `htmx-indicator` | A dynamically generated class that will toggle visible (opacity:1) when a `htmx-request` class is present
+| `htmx-request` | Applied to either the element or the element specified with [`hx-indicator`](@/attributes/hx-indicator.md) while a request is ongoing
+| `htmx-settling` | Applied to a target after content is swapped, removed after it is settled. The duration can be modified via [`hx-swap`](@/attributes/hx-swap.md).
+| `htmx-swapping` | Applied to a target before any content is swapped, removed after it is swapped. The duration can be modified via [`hx-swap`](@/attributes/hx-swap.md).
+
+
+
+| Header | Description |
+|--------|-------------|
+| `HX-Boosted` | indicates that the request is via an element using [hx-boost](@/attributes/hx-boost.md)
+| `HX-Current-URL` | the current URL of the browser
+| `HX-History-Restore-Request` | "true" if the request is for history restoration after a miss in the local history cache
+| `HX-Prompt` | the user response to an [hx-prompt](@/attributes/hx-prompt.md)
+| `HX-Request` | always "true"
+| `HX-Target` | the `id` of the target element if it exists
+| `HX-Trigger-Name` | the `name` of the triggered element if it exists
+| `HX-Trigger` | the `id` of the triggered element if it exists
+
+
+
+| Header | Description |
+|------------------------------------------------------|-------------|
+| [`HX-Location`](@/headers/hx-location.md) | allows you to do a client-side redirect that does not do a full page reload
+| [`HX-Push-Url`](@/headers/hx-push-url.md) | pushes a new url into the history stack
+| [`HX-Redirect`](@/headers/hx-redirect.md) | can be used to do a client-side redirect to a new location
+| `HX-Refresh` | if set to "true" the client-side will do a full refresh of the page
+| [`HX-Replace-Url`](@/headers/hx-replace-url.md) | replaces the current URL in the location bar
+| `HX-Reswap` | allows you to specify how the response will be swapped. See [hx-swap](@/attributes/hx-swap.md) for possible values
+| `HX-Retarget` | a CSS selector that updates the target of the content update to a different element on the page
+| `HX-Reselect` | a CSS selector that allows you to choose which part of the response is used to be swapped in. Overrides an existing [`hx-select`](@/attributes/hx-select.md) on the triggering element
+| [`HX-Trigger`](@/headers/hx-trigger.md) | allows you to trigger client-side events
+| [`HX-Trigger-After-Settle`](@/headers/hx-trigger.md) | allows you to trigger client-side events after the settle step
+| [`HX-Trigger-After-Swap`](@/headers/hx-trigger.md) | allows you to trigger client-side events after the swap step
+
+
+
+## Event Reference {#events}
+
+
+
+| Event | Description |
+|-------|-------------|
+| [`htmx:abort`](@/events.md#htmx:abort) | send this event to an element to abort a request
+| [`htmx:afterOnLoad`](@/events.md#htmx:afterOnLoad) | triggered after an AJAX request has completed processing a successful response
+| [`htmx:afterProcessNode`](@/events.md#htmx:afterProcessNode) | triggered after htmx has initialized a node
+| [`htmx:afterRequest`](@/events.md#htmx:afterRequest) | triggered after an AJAX request has completed
+| [`htmx:afterSettle`](@/events.md#htmx:afterSettle) | triggered after the DOM has settled
+| [`htmx:afterSwap`](@/events.md#htmx:afterSwap) | triggered after new content has been swapped in
+| [`htmx:beforeCleanupElement`](@/events.md#htmx:beforeCleanupElement) | triggered before htmx [disables](@/attributes/hx-disable.md) an element or removes it from the DOM
+| [`htmx:beforeOnLoad`](@/events.md#htmx:beforeOnLoad) | triggered before any response processing occurs
+| [`htmx:beforeProcessNode`](@/events.md#htmx:beforeProcessNode) | triggered before htmx initializes a node
+| [`htmx:beforeRequest`](@/events.md#htmx:beforeRequest) | triggered before an AJAX request is made
+| [`htmx:beforeSwap`](@/events.md#htmx:beforeSwap) | triggered before a swap is done, allows you to configure the swap
+| [`htmx:beforeSend`](@/events.md#htmx:beforeSend) | triggered just before an ajax request is sent
+| [`htmx:beforeTransition`](@/events.md#htmx:beforeTransition) | triggered before the [View Transition](https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API) wrapped swap occurs
+| [`htmx:configRequest`](@/events.md#htmx:configRequest) | triggered before the request, allows you to customize parameters, headers
+| [`htmx:confirm`](@/events.md#htmx:confirm) | triggered after a trigger occurs on an element, allows you to cancel (or delay) issuing the AJAX request
+| [`htmx:historyCacheError`](@/events.md#htmx:historyCacheError) | triggered on an error during cache writing
+| [`htmx:historyCacheMiss`](@/events.md#htmx:historyCacheMiss) | triggered on a cache miss in the history subsystem
+| [`htmx:historyCacheMissError`](@/events.md#htmx:historyCacheMissError) | triggered on a unsuccessful remote retrieval
+| [`htmx:historyCacheMissLoad`](@/events.md#htmx:historyCacheMissLoad) | triggered on a successful remote retrieval
+| [`htmx:historyRestore`](@/events.md#htmx:historyRestore) | triggered when htmx handles a history restoration action
+| [`htmx:beforeHistorySave`](@/events.md#htmx:beforeHistorySave) | triggered before content is saved to the history cache
+| [`htmx:load`](@/events.md#htmx:load) | triggered when new content is added to the DOM
+| [`htmx:noSSESourceError`](@/events.md#htmx:noSSESourceError) | triggered when an element refers to a SSE event in its trigger, but no parent SSE source has been defined
+| [`htmx:onLoadError`](@/events.md#htmx:onLoadError) | triggered when an exception occurs during the onLoad handling in htmx
+| [`htmx:oobAfterSwap`](@/events.md#htmx:oobAfterSwap) | triggered after an out of band element as been swapped in
+| [`htmx:oobBeforeSwap`](@/events.md#htmx:oobBeforeSwap) | triggered before an out of band element swap is done, allows you to configure the swap
+| [`htmx:oobErrorNoTarget`](@/events.md#htmx:oobErrorNoTarget) | triggered when an out of band element does not have a matching ID in the current DOM
+| [`htmx:prompt`](@/events.md#htmx:prompt) | triggered after a prompt is shown
+| [`htmx:pushedIntoHistory`](@/events.md#htmx:pushedIntoHistory) | triggered after a url is pushed into history
+| [`htmx:replacedInHistory`](@/events.md#htmx:replacedInHistory) | triggered after a url is replaced in history
+| [`htmx:responseError`](@/events.md#htmx:responseError) | triggered when an HTTP response error (non-`200` or `300` response code) occurs
+| [`htmx:sendAbort`](@/events.md#htmx:sendAbort) | triggered when a request is aborted
+| [`htmx:sendError`](@/events.md#htmx:sendError) | triggered when a network error prevents an HTTP request from happening
+| [`htmx:sseError`](@/events.md#htmx:sseError) | triggered when an error occurs with a SSE source
+| [`htmx:sseOpen`](/events#htmx:sseOpen) | triggered when a SSE source is opened
+| [`htmx:swapError`](@/events.md#htmx:swapError) | triggered when an error occurs during the swap phase
+| [`htmx:targetError`](@/events.md#htmx:targetError) | triggered when an invalid target is specified
+| [`htmx:timeout`](@/events.md#htmx:timeout) | triggered when a request timeout occurs
+| [`htmx:validation:validate`](@/events.md#htmx:validation:validate) | triggered before an element is validated
+| [`htmx:validation:failed`](@/events.md#htmx:validation:failed) | triggered when an element fails validation
+| [`htmx:validation:halted`](@/events.md#htmx:validation:halted) | triggered when a request is halted due to validation errors
+| [`htmx:xhr:abort`](@/events.md#htmx:xhr:abort) | triggered when an ajax request aborts
+| [`htmx:xhr:loadend`](@/events.md#htmx:xhr:loadend) | triggered when an ajax request ends
+| [`htmx:xhr:loadstart`](@/events.md#htmx:xhr:loadstart) | triggered when an ajax request starts
+| [`htmx:xhr:progress`](@/events.md#htmx:xhr:progress) | triggered periodically during an ajax request that supports progress events
+
+
+
+## JavaScript API Reference {#api}
+
+
+
+| Method | Description |
+|-------|-------------|
+| [`htmx.addClass()`](@/api.md#addClass) | Adds a class to the given element
+| [`htmx.ajax()`](@/api.md#ajax) | Issues an htmx-style ajax request
+| [`htmx.closest()`](@/api.md#closest) | Finds the closest parent to the given element matching the selector
+| [`htmx.config`](@/api.md#config) | A property that holds the current htmx config object
+| [`htmx.createEventSource`](@/api.md#createEventSource) | A property holding the function to create SSE EventSource objects for htmx
+| [`htmx.createWebSocket`](@/api.md#createWebSocket) | A property holding the function to create WebSocket objects for htmx
+| [`htmx.defineExtension()`](@/api.md#defineExtension) | Defines an htmx [extension](https://htmx.org/extensions)
+| [`htmx.find()`](@/api.md#find) | Finds a single element matching the selector
+| [`htmx.findAll()` `htmx.findAll(elt, selector)`](@/api.md#find) | Finds all elements matching a given selector
+| [`htmx.logAll()`](@/api.md#logAll) | Installs a logger that will log all htmx events
+| [`htmx.logger`](@/api.md#logger) | A property set to the current logger (default is `null`)
+| [`htmx.off()`](@/api.md#off) | Removes an event listener from the given element
+| [`htmx.on()`](@/api.md#on) | Creates an event listener on the given element, returning it
+| [`htmx.onLoad()`](@/api.md#onLoad) | Adds a callback handler for the `htmx:load` event
+| [`htmx.parseInterval()`](@/api.md#parseInterval) | Parses an interval declaration into a millisecond value
+| [`htmx.process()`](@/api.md#process) | Processes the given element and its children, hooking up any htmx behavior
+| [`htmx.remove()`](@/api.md#remove) | Removes the given element
+| [`htmx.removeClass()`](@/api.md#removeClass) | Removes a class from the given element
+| [`htmx.removeExtension()`](@/api.md#removeExtension) | Removes an htmx [extension](https://htmx.org/extensions)
+| [`htmx.swap()`](@/api.md#swap) | Performs swapping (and settling) of HTML content
+| [`htmx.takeClass()`](@/api.md#takeClass) | Takes a class from other elements for the given element
+| [`htmx.toggleClass()`](@/api.md#toggleClass) | Toggles a class from the given element
+| [`htmx.trigger()`](@/api.md#trigger) | Triggers an event on an element
+| [`htmx.values()`](@/api.md#values) | Returns the input values associated with the given element
+
+
+
+
+## Configuration Reference {#config}
+
+Htmx has some configuration options that can be accessed either programmatically or declaratively. They are
+listed below:
+
+
+
+| Config Variable | Info |
+|---------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `htmx.config.historyEnabled` | defaults to `true`, really only useful for testing |
+| `htmx.config.historyCacheSize` | defaults to 10 |
+| `htmx.config.refreshOnHistoryMiss` | defaults to `false`, if set to `true` htmx will issue a full page refresh on history misses rather than use an AJAX request |
+| `htmx.config.defaultSwapStyle` | defaults to `innerHTML` |
+| `htmx.config.defaultSwapDelay` | defaults to 0 |
+| `htmx.config.defaultSettleDelay` | defaults to 20 |
+| `htmx.config.includeIndicatorStyles` | defaults to `true` (determines if the indicator styles are loaded) |
+| `htmx.config.indicatorClass` | defaults to `htmx-indicator` |
+| `htmx.config.requestClass` | defaults to `htmx-request` |
+| `htmx.config.addedClass` | defaults to `htmx-added` |
+| `htmx.config.settlingClass` | defaults to `htmx-settling` |
+| `htmx.config.swappingClass` | defaults to `htmx-swapping` |
+| `htmx.config.allowEval` | defaults to `true`, can be used to disable htmx's use of eval for certain features (e.g. trigger filters) |
+| `htmx.config.allowScriptTags` | defaults to `true`, determines if htmx will process script tags found in new content |
+| `htmx.config.inlineScriptNonce` | defaults to `''`, meaning that no nonce will be added to inline scripts |
+| `htmx.config.inlineStyleNonce` | defaults to `''`, meaning that no nonce will be added to inline styles |
+| `htmx.config.attributesToSettle` | defaults to `["class", "style", "width", "height"]`, the attributes to settle during the settling phase |
+| `htmx.config.wsReconnectDelay` | defaults to `full-jitter` |
+| `htmx.config.wsBinaryType` | defaults to `blob`, the [the type of binary data](https://developer.mozilla.org/docs/Web/API/WebSocket/binaryType) being received over the WebSocket connection |
+| `htmx.config.disableSelector` | defaults to `[hx-disable], [data-hx-disable]`, htmx will not process elements with this attribute on it or a parent |
+| `htmx.config.disableInheritance` | defaults to `false`. If it is set to `true`, the inheritance of attributes is completely disabled and you can explicitly specify the inheritance with the [hx-inherit](@/attributes/hx-inherit.md) attribute.
+| `htmx.config.withCredentials` | defaults to `false`, allow cross-site Access-Control requests using credentials such as cookies, authorization headers or TLS client certificates |
+| `htmx.config.timeout` | defaults to 0, the number of milliseconds a request can take before automatically being terminated |
+| `htmx.config.scrollBehavior` | defaults to 'instant', the scroll behavior when using the [show](@/attributes/hx-swap.md#scrolling-scroll-show) modifier with `hx-swap`. The allowed values are `instant` (scrolling should happen instantly in a single jump), `smooth` (scrolling should animate smoothly) and `auto` (scroll behavior is determined by the computed value of [scroll-behavior](https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-behavior)). |
+| `htmx.config.defaultFocusScroll` | if the focused element should be scrolled into view, defaults to false and can be overridden using the [focus-scroll](@/attributes/hx-swap.md#focus-scroll) swap modifier. |
+| `htmx.config.getCacheBusterParam` | defaults to false, if set to true htmx will append the target element to the `GET` request in the format `org.htmx.cache-buster=targetElementId` |
+| `htmx.config.globalViewTransitions` | if set to `true`, htmx will use the [View Transition](https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API) API when swapping in new content. |
+| `htmx.config.methodsThatUseUrlParams` | defaults to `["get", "delete"]`, htmx will format requests with these methods by encoding their parameters in the URL, not the request body |
+| `htmx.config.selfRequestsOnly` | defaults to `true`, whether to only allow AJAX requests to the same domain as the current document |
+| `htmx.config.ignoreTitle` | defaults to `false`, if set to `true` htmx will not update the title of the document when a `title` tag is found in new content |
+| `htmx.config.scrollIntoViewOnBoost` | defaults to `true`, whether or not the target of a boosted element is scrolled into the viewport. If `hx-target` is omitted on a boosted element, the target defaults to `body`, causing the page to scroll to the top. |
+| `htmx.config.triggerSpecsCache` | defaults to `null`, the cache to store evaluated trigger specifications into, improving parsing performance at the cost of more memory usage. You may define a simple object to use a never-clearing cache, or implement your own system using a [proxy object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Proxy) |
+| `htmx.config.responseHandling` | the default [Response Handling](@/docs.md#response-handling) behavior for response status codes can be configured here to either swap or error |
+| `htmx.config.allowNestedOobSwaps` | defaults to `true`, whether to process OOB swaps on elements that are nested within the main response element. See [Nested OOB Swaps](@/attributes/hx-swap-oob.md#nested-oob-swaps). |
+
+
+
+You can set them directly in javascript, or you can use a `meta` tag:
+
+```html
+
+```# 🗿 Surreal
+### Tiny jQuery alternative for plain Javascript with inline [Locality of Behavior](https://htmx.org/essays/locality-of-behaviour/)!
+
+
+(Art by [shahabalizadeh](https://www.deviantart.com/shahabalizadeh))
+
+
+## Why does this exist?
+
+For devs who love ergonomics! You may appreciate Surreal if:
+
+* You want to stay as close as possible to Vanilla JS.
+* Hate typing `document.querySelector` over.. and over..
+* Hate typing `addEventListener` over.. and over..
+* Really wish `document.querySelectorAll` had Array functions..
+* Really wish `this` would work in any inline `
+
+```
+
+See the [Live Example](https://gnat.github.io/surreal/example.html)! Then [view source](https://github.com/gnat/surreal/blob/main/example.html).
+
+## 🎁 Install
+
+Surreal is only 320 lines. No build step. No dependencies.
+
+[📥 Download](https://raw.githubusercontent.com/gnat/surreal/main/surreal.js) into your project, and add `` in your ``
+
+Or, 🌐 via CDN: ``
+
+## ⚡ Usage
+
+### 🔍️ DOM Selection
+
+* Select **one** element: `me(...)`
+ * Can be any of:
+ * CSS selector: `".button"`, `"#header"`, `"h1"`, `"body > .block"`
+ * Variables: `body`, `e`, `some_element`
+ * Events: `event.currentTarget` will be used.
+ * Surreal selectors: `me()`,`any()`
+ * Choose the start location in the DOM with the 2nd arg. (Default: `document`)
+ * 🔥 `any('button', me('#header')).classAdd('red')`
+ * Add `.red` to any `# 🌘 CSS Scope Inline
+
+
+(Art by [shahabalizadeh](https://www.artstation.com/artwork/zDgdd))
+
+## Why does this exist?
+
+* You want an easy inline vanilla CSS experience without Tailwind CSS.
+* Hate creating unique class names over.. and over.. to use once.
+* You want to co-locate your styles for ⚡️ [Locality of Behavior (LoB)](https://htmx.org/essays/locality-of-behaviour/)
+* You wish `this` would work in `
+
+
+```
+See the [Live Example](https://gnat.github.io/css-scope-inline/example.html)! Then [view source](https://github.com/gnat/css-scope-inline/blob/main/example.html).
+
+## 🌘 How does it work?
+
+This uses `MutationObserver` to monitor the DOM, and the moment a `
+ red
+
green
+
green
+
green
+
yellow
+
blue
+
green
+
green
+
+
+
+ red
+
green
+
green
+
green
+
yellow
+
blue
+
green
+
green
+
+```
+
+### CSS variables and child elements
+At first glance, **Tailwind Example 2** looks very promising! Exciting ...but:
+* 🔴 **Every child style requires an explicit selector.**
+ * Tailwinds' shorthand advantages sadly disappear.
+ * Any more child styles added in Tailwind will become longer than vanilla CSS.
+ * This limited example is the best case scenario for Tailwind.
+* 🔴 Not visible on github: **no highlighting for properties and units** begins to be painful.
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+```
+## 🔎 Technical FAQ
+* Why do you use `querySelectorAll()` and not just process the `MutationObserver` results directly?
+ * This was indeed the original design; it will work well up until you begin recieving subtrees (ex: DOM swaps with [htmx](https://htmx.org), ajax, jquery, etc.) which requires walking all subtree elements to ensure we do not miss a `