🗿
Surreal - Hyper minimalist jQuery alternative
(Art by shahabalizadeh)
💙
Why does this exist?
For devs who love ergonomics!
If you agree with any of the following, you may appreciate Surreal:
- Love staying as close 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 childtags.
- Love having no build step to speak of.
- Love fewer layers, and a snappy UI.
- Enjoyed using jQuery selector syntax.
- Are aware of the cargo cult.
✈️
✨
What advantages does it bring to the table?
-
🔗 Call chaining. -
♻️ Seamlessly handle an individual element OR arrays of elements.- Surreal functions operate agnostically on
HTMLElement
orNodeList
(orArray
ofHTMLElement
). - For your own functions, select one element directly:
me()
or many elements:any()
- Both
me()
andany()
can chain with any Surreal function.
- Both
- Elements from
me()
can be accessed directly as a single element (a betterquerySelector()
or$
) - Elements from
any()
can use any of these:forEach
/filter
/map
/reduce
(a betterquerySelectorAll()
or$$
)
- Surreal functions operate agnostically on
-
❤️🔥 ChoosecamelCase
(standard, jQuery) ORsnake_case
(Python, Rust, PHP, Ruby, SQL, CSS, templates).- No more forcing of styles you may not want:
class_add
is just an alias ofclassAdd
- No more forcing of styles you may not want:
-
⚡️ Locality of Behavior (LoB) is fully supported.me()
can be used insidetags to get the current element without a unique identifier -- no class, no id needed! We drastically upgraded your
this
!
Do surreal things with Locality of Behavior like:
<label for="file-input" >
<div class="uploader">div>
<script>
me().on("dragover", ev => { halt(ev); me(ev).classAdd('.hover'); console.log("Files in drop zone.") })
me().on("dragleave", ev => { halt(ev); me(ev).classAdd('.hover'); console.log("Files left drop zone.") })
me().on("drop", ev => { halt(ev); me(ev).classRemove('.hover').classAdd('.loading'); me('#file-input').attribute('files', ev.dataTransfer.files); me('#form').trigger('change') })
script>
label>
👁️
Live Example
Get a taste- see the Showcase! Then view source.
🎁
Installation
Surreal is a dependency-free, browser-oriented javascript library. Download Surreal and drag surreal.js
into the appropriate directory of your project. Using it is as simple as adding a tag to your document head. No need for complicated build steps or systems.
<script src="surreal.js">script>
🤔
Why choose me()
and any()
over $
and $$
- No ambiguity unlike jQuery's approach of
$
for both single elements and Arrays. Less need for sanity checks. - Readability. English-like and self documenting.
- Same verbbage as Hyperscript making this an excellent transitional library.
- It can be far less wordy to work with elements directly instead of an Array.
📚️
Inspired by
- jQuery for the chainable syntax we all love.
- BlingBling.js for modern minimalism.
- Bliss.js for a focus on single elements and extensibility.
- Hyperscript for Locality of Behavior and awesome ergonomics.
- Shout out to Umbrella, Cash, Zepto- Not quite as ergonomic or extensible.
🔥
Usage Overview
🔍️
DOM Selection
You want one element directly.
me(...)
me()
Get the current element.- Provides Locality of Behavior in
without a unique identifier (no class, no id).
- Provides Locality of Behavior in
me(body)
Get only one element.me("button")
If more than one match, get only the first one.
You want one or more elements as an Array.
any(...)
Convert between a direct single element and an Array of elements using any(me())
, me(any(".thing"))
...
can be any of:
- CSS selector string:
"#header"
,"button"
,".red_label"
,"body > .block"
- Variables:
body
,elt
,some_element
- Events:
event.target
will be used. - Themselves:
me()
,any()
start=
parameter provides a starting point to select from, default isdocument
.any('button', start='header').classAdd('red')
⚙️
DOM Functions
-
♻️ All can use either single elements or arrays of elements transparently! -
🔗 Chaining offme()
andany()
and many others supported. -
🌐 Global conveniences can be turned off if desired by removingglobalsAdd()
globalsAdd()
will automatically warn about any clobbering issues.
🟢
Style A (
🔗
Chaining)
-
🔥 me().classAdd('red')
😎 RECOMMENDED STYLE - No convenience globals:
$.me().classAdd('red')
🟠
Style B (Classic)
-
🔥 classAdd(me(), 'red')
- No convenience globals:
$.classAdd($.me(), 'red')
Great? See: Quick Start and Reference and No Surreal Needed
🔥
Quick Start
- Add a class
me().classAdd('red')
any("button").classAdd('red')
- Events
me().on("click", ev => me(ev).fade_out() )
on(any('button'), 'click', ev => { me(ev).styles('color: red') })
- Run functions over elements.
any('button').run(_ => { alert(_) })
- Styles / CSS
me().styles('color: red')
me().styles({ 'color':'red', 'background':'blue' })
- Attributes
me().attribute('active', true)
Timeline animations without any libraries.
<div>I change color every second. <script> // Locality of Behavior me().on("click", async ev => { me(ev).styles({ "transition": "background 1s" }) await sleep(1000) me(ev).styles({ "background": "red" }) await sleep(1000) me(ev).styles({ "background": "green" }) await sleep(1000) me(ev).styles({ "background": "blue" }) await sleep(1000) me(ev).styles({ "background": "none" }) await sleep(1000) me(ev).remove() }) script> div>