{"id":23814380,"url":"https://github.com/stuartpb/pwalls-spec","last_synced_at":"2026-01-29T03:02:47.116Z","repository":{"id":139972085,"uuid":"40202504","full_name":"stuartpb/pwalls-spec","owner":"stuartpb","description":"HTML/CSS/DOM Parts and Walls Proposal","archived":false,"fork":false,"pushed_at":"2015-08-24T00:02:58.000Z","size":188,"stargazers_count":1,"open_issues_count":4,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-01-02T03:47:21.880Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stuartpb.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-08-04T18:36:42.000Z","updated_at":"2019-07-26T10:30:17.000Z","dependencies_parsed_at":"2023-03-13T10:44:48.360Z","dependency_job_id":null,"html_url":"https://github.com/stuartpb/pwalls-spec","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stuartpb%2Fpwalls-spec","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stuartpb%2Fpwalls-spec/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stuartpb%2Fpwalls-spec/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stuartpb%2Fpwalls-spec/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stuartpb","download_url":"https://codeload.github.com/stuartpb/pwalls-spec/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240079640,"owners_count":19744726,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-01-02T03:47:24.275Z","updated_at":"2026-01-29T03:02:47.036Z","avatar_url":"https://github.com/stuartpb.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# HTML Parts and Walls\n\n## Status\n\nThis document is \"pre-specification\" which means that I haven't even figured out enough spec bureaucracy to give this document a proper status. It's been [posted to the WICG Discourse](http://discourse.wicg.io/t/html-parts-and-roots/1032), and that's about it.\n\n## Overview\n\nThis document proposes two new attributes that, like `class` and `id`, may be applied to any element in HTML:\n\n- `wall`, a boolean attribute specifying that the element is to be treated as a boundary for the purposes of the `getPart()` function and the Walled Descendant Selector defined below.\n- `part`, an attribute with a name value, following the same uniqueness and traversal constraints within walled boundaries as `id` has within document boundaries.\n  - `id` may still be defined on an element with `part`, as they have different access implications. (A framework or polyfill may generate `id` values to uniquely identify every element in a document: this will not affect `part`.)\n\n## Motivation\n\nIt's still not great to write components in HTML:\n\n- CSS selectors always applying globally leads to unduly elaborate namespacing schemes like BEM.\n- There's still no real good solution for addressing *unique children* of an element.\n\nShadow DOM is supposed to solve this, but it comes with a handful of even worse problems:\n\n- The isolated context cuts you off from reusing your page styles.\n- Just because I want to style for a component, doesn't mean I want to make its children inaccessible to `getElementsByTagName` \u0026c.\n- Styles defined by the page to apply *within* the context of Shadow DOM are impossible (the closest this came to a solution was `/deep/`, which only served to bring all the contextual problems of CSS selectors back and undo the most significant guarantee Shadow DOM is supposed to provide).\n- Indexing elements *within* the component requires you to either go full-hog about designing the inner HTML to depend on Shadow DOM's ID isolation, or use clumsy class-based addressing techniques.\n- Shadow DOM contexts can't be created declaratively (without Custom Elements, which require lots of JS and bring further constraints).\n\nWalled elements introduce a lighter option than Shadow DOM contexts for *basic* encapsulation. (For styling within heavier encapsulation, the Walled Descendant combinator may *also* be used for *crossing* Shadow DOM boundaries.) It provides a facility page authors may use to create a hierarchy *in the context of their page*, allowing them to have simple and straightforward access *within the boundaries of their hierarchy*, without being concerned about namespacing *at every level* (the scope of concern for namespace schemes can be limited to selecting the proot).\n\n## DOM Parts\n\nElements have a `getPart()` function, which works similarly to how `getElementById` or `getElementByClassName[0]` works (doing a depth-first search under the element), except looking for `part` rather than `id` and avoiding traversal beyond wall boundaries (as well as the document boundaries which all traversal algorithms avoid).\n\nExample: say I have this HTML:\n\n```html\n\u003cdiv id=\"fig1\" class=\"lotto\" wall\u003e\n  \u003cdiv class=\"lid\"\u003e\n    \u003cspan part=\"timer\" id=\"fig2\"\u003e108:00\u003c/span\u003e\n  \u003c/div\u003e\n  \u003cdiv part=\"bubble\" wall id=\"fig3\"\u003e\n    \u003cdiv part=\"funnel\" id=\"fig4\"\u003e\n      \u003cspan class=\"ball\"\u003e42\u003c/span\u003e\n    \u003c/div\u003e\n    \u003cdiv part=\"track\" id=\"fig5\"\u003e\n      \u003cspan class=\"ball\"\u003e23\u003c/span\u003e\n      \u003cspan class=\"ball\"\u003e16\u003c/span\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n  \u003cdiv part=\"track\" id=\"fig6\"\u003e\n    \u003cspan class=\"ball\"\u003e4\u003c/span\u003e\n    \u003cspan class=\"ball\"\u003e8\u003c/span\u003e\n    \u003cspan class=\"ball\"\u003e15\u003c/span\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n```\n\n(Note: This element would normally be created as one of many, having no IDs defined. The IDs are purely for illustrative purposes in the following description.)\n\nLet `fig1 = document.getElementById('fig1')`.\n\nRunning `fig1.getPart('timer')` would return the element with the ID `fig2`, as that is the unique (first) element under `fig1` with the `part` attribute value `timer`.\n\nRunning `fig1.getPart('bubble')` would return the element with the ID `fig3`, as that is the unique (first) element under `fig1` with the `part` attribute value `bubble`. (The fact that the element itself has a `wall` value does not stop the *element itself* from being found.)\n\nRunning `fig1.getPart('funnel')` would return `null`, as the only element with the `part` attribute value `funnel` underneath `fig1` is underneath the element with the ID `fig3`, which has the `wall` attribute defined, causing the search to not recurse further into that element's descendants. (Getting the element with the ID `fig4` would require starting the search from its first ancestor with the `wall` attribute, namely the element with the ID `fig3`, ie. `fig1.getPart('bubble').getPart('funnel')`.\n\nRunning `fig1.getPart('track')` would return would return the element with the ID `fig6`, as that is the unique (first) element under `fig1` with the `part` attribute value `track` that is not underneath an element (namely, the element with the ID `fig3`) which has the `wall` attribute defined (which causes the search to not recurse further into that element's descendants, hence skipping the element with the ID `fig5`).\n\nRunning `fig1.getPart('bubble').getPart('track')` would return the element with the ID `fig5`, as that is the unique (first) element under `fig1.getPart('bubble')` with the `part` attribute value `track`.\n\n## The Walled Descendant Combinator for CSS Selectors\n\nA `|\u003e` sequence may be used after a [compound selector](https://drafts.csswg.org/selectors-4/#compound), to define a wall or Shadow DOM boundary crossing. The element matched on the LHS of the combinator must have the `wall` attribute defined or contain a Shadow DOM. The compound selector to the right of the `|\u003e` only matches descendants of the LHS that *do not cross* further walls (though the matched element may itself have a `wall` attribute specified, the descendants of a child with `wall` specified *will not* match the combinator). The `#` character, after a `|\u003e`, refers to *either IDs or parts* within the LHS walled context (the specificity is increased as an ID selector for either kind of match).\n\nNote: It is important to note that *further combinators left of the walled desecendant combinator* may traverse *any number* of walls. Walls *only* come into play *around the walled descendant combinator*. Any non-walled descendant combinators (namely, the whitespace or `\u003e\u003e` \"general\" descendant combinator), as before, *are not separated* by walls.\n\n## Differences between walled elements and Shadow DOM\n\n- Elements under a walled element are still selected by selectors in the top-level document, as well as functions like `getElementsByClassName`.\n- Walls can be defined without JS.\n- Child elements may be moved between walled elements without having to create a copy with `importNode`, discard the old node, and expecting things that `importNode` doesn't copy to break.\n\n## Differences between `part` and `class` or `name`\n\n- Unlike class names, parts are expected to be unique within the context of their wall (which allows for optimizations to `getPart`, as well as warnings in validators, and other developer tool enhancements).\n- Part names under walls do *not* have to be considered in the global namespace, unlike class names. (Similarly, part names do *not* have to correspond to the name used for a value when submitting a form.)\n- Unlike `getElementsByName` or `getElementsByClassName`, `getPart` is restricted to wall boundaries.\n\n## Extensions to existing elements\n\nA standard structure for the standard elements UAs currently construct within Shadow DOM could be defined, using `part` attributes to refer to a hierarchy of their components, for access in styling, as an alternative to non-standard vendor-prefixed pseudo-elements, as we currently use. (This includes the sub-components of scrollbars, which would remain pseudo-elements, but be standardized as pseudo-elements containing walls.)\n\n## Example: Doctor Listings \n\n```html\n\u003chtml\u003e\n\u003chead\u003e\n\u003cstyle\u003e\n/* TODO: finish example stylesheet */\n.profile |\u003e #photo {\n\n}\n.profile |\u003e #name {\n\n}\n.profile |\u003e #bio {\n\n}\n\u003c/style\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n\u003cdiv id=\"profiles\"\u003e\n  \u003cdiv class=\"profile\" wall\u003e\n    \u003cimg src=\"person-a.jpg\" part=\"avatar\"\u003e\n    \u003cdiv part=\"name\"\u003eFoo Bar\u003c/div\u003e\n    \u003cp part=\"bio\"\u003elorem ipsum\u003c/p\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"profile\" wall\u003e\n    \u003cimg src=\"person-b.jpg\" part=\"avatar\"\u003e\n    \u003cdiv part=\"name\"\u003eBoo Car\u003c/div\u003e\n    \u003cp part=\"bio\"\u003elorem ipsum\u003c/p\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"profile\" wall\u003e\n    \u003cimg src=\"person-c.jpg\" part=\"avatar\"\u003e\n    \u003cdiv part=\"name\"\u003eKenny Baz\u003c/div\u003e\n    \u003cp part=\"bio\"\u003elorem ipsum\u003c/p\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\n## Example: Chat UI (initial content with HTML template)\n\n```html\n\u003chtml\u003e\n\u003chead\u003e\n\u003cstyle\u003e\n/* TODO: finish example stylesheet */\n.message-card|\u003e #avatar {\n\n}\n.message-card|\u003e #name {\n\n}\n.message-card|\u003e #message {\n\n}\n\u003c/style\u003e\n\u003ctemplate id=\"message-card-template\"\u003e\n  \u003cdiv class=\"message-card\" wall\u003e\n    \u003cimg part=\"avatar\"\u003e\n    \u003cdiv part=\"name\"\u003e\u003c/div\u003e\n    \u003cdiv part=\"message\"\u003e\u003c/div\u003e\n  \u003c/div\u003e\n\u003c/template\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n\u003cdiv id=\"messages\"\u003e\u003c/div\u003e\n\u003cscript\u003e\n// TODO: write script\n\u003c/script\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\n## Example: Chat UI (live snapshot of variant using no HTML template)\n\n```html\n\u003chtml\u003e\n\u003chead\u003e\n\u003clink rel=\"stylesheet\" href=\"same-style-as-last-template.css\"\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n\u003cdiv id=\"messages\"\u003e\n  \u003cdiv class=\"message-card\" id=\"7cf00c89-800f-495b-9e44-a2ffd9df817c\" wall\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"message-card\" id=\"26888874-dbe9-4efc-8f88-873af7139a4d\" wall\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"message-card\" id=\"5c212dc7-5d73-4759-a466-589a08d5a98e\" wall\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"message-card\" id=\"ed8818ff-353d-4219-a28f-a97b531e95f2\" wall\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"message-card\" id=\"331bb13b-7071-4d69-9b04-fb62502a5601\" wall\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"message-card\" id=\"7fc6ee0c-85d2-47e2-a8f4-4f499d44bfdb\" wall\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"message-card\" id=\"95ca156f-8e59-4372-8e6f-bff9c8a7c4ac\" wall\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"message-card\" id=\"cd3ac0ae-925f-45e8-a1e7-98e1b215ba9e\" wall\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003cscript\u003e\n// TODO: write script\n\u003c/script\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\n## TODO\n\n- Everything marked \"TODO\" above.\n- Add proposals for what the standard element parts look like.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstuartpb%2Fpwalls-spec","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstuartpb%2Fpwalls-spec","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstuartpb%2Fpwalls-spec/lists"}