The JavaScript ecosystem is always evolving and it is time for another wave of the future.
We all loved it when jQuery was baked into browsers as ...
For further actions, you may consider blocking this person and/or reporting abuse
I'm looking at your initial issues and I don't think they're issues I've ever considered.
So I'm not sure why this is a problem. Yes, they do different things, but that's normal - you write different functions to do different things. I think of it as
querySelectorbeing a bit of sugar forquerySelectorAll(...)[0]. If they did the same thing, then there would be no point in one of them existing!Destructuring the return value from
querySelectorAllis definitely something I've never thought of, probably because I don't think it makes sense outside a very narrow use case.Every time you select something with multiple rules, there's a Venn diagram of DOM elements and their selectors. Unless you're identifying everything with a unique class.
Maybe your e-commerce forms all need some CSRF logic, so you ask something like,
querySelectorAll('form.stripe, form.paypal, form.foobarFintech'). You don't want to have to destructure that and iterate through the results, you want a list of relevant forms to bind to.I'll admit,
querySelectorAllfalls down a bit here because it doesn't return an array, but it's so common to spread it into one that it doesn't really cause much friction.Adding a new DSL for things like
$select('.post[remove|class=flex bold]')is another odd choice, to me:First, it's baking an action into the parameter of a function named like a getter. I would rather take the return value from the getter and perform an action on it, or name the function something else.
Secondly, I can't guess from looking at it whether it removes "flex" OR "bold", "flex" AND "bold", or "flex space bold" (i.e. whether order counts).
Finally,
$select('.post[5]')is reinventingdocument.querySelectorAll('.post')[5]except I can't intuit what exception handling there is.the idea that you ship less js because
$selectis shorter thandocument.querySelectorAllyet you need to pull in an entire library to use$selectis a strange one too$select alone is written in few lines of code and you don't write less code because $select() is shorter — it is far from that but you have to use it to know what I am saying.
In most projects , you will end up writing more lines of code if you don't use $select(). That is why it scales well and still comes with several goodies to enjoy. 🤩
This right here folks!
First, they do not do the same thing — check the docs I attached for confirmation.
Second, I will say you're right not to deny your experience but if you really want to have a better experience just try it. Then, you will have balanced insight concerning both APIs. So check it out and use it, then let's have this discussion.
Also, you can get returned elements and still do whatever you want with them because $select() always returns all the elements it selects.
It can filter, search the DOM directly and more. And you can use it comfortably, directly, concisely and flexibly in html via onclick, onhover and more.
Parent children input component is a good example of how to use it and you can check its code on codesandbox.
Thank you!
Could you help me out with the source for that preview? It looks like it's a page embedding a ton of minimised scripts.
So, let's abandon all SOLID principles and move everything from javascript syntax to something else?
Is deleting something in a function called
selectreally a great idea? Are we deleting from the selection or from DOM?It's convenient. But is it useful?
It is both convenient and useful. It does both.
You can filter, search, order and more. Check the docs to have a better understanding of it.
You're moving away from both JavaScript and CSS by trying to cram too much functionality into a "better querrySelector" while breaking its single responsibility: return nodes matching a CSS selector. For example:
The CSS selector
'.post, .comment'means "all nodes with either class=post OR class=comment", but instead $select returns all nodes with class=post AND all nodes with class=comment. I realize the result contains the same nodes but I request one list and I get two. Not cool. And if there's a<div class='post comment'>and I get it in both lists, that may or may not be what I expect.I understand, CSS selector syntax may not be the most intuitive but it's well established and documented. And it would be expected that the same selector returns the same node list everywhere. E.g.
'*[something]'is a valid attribute selector but'*[5]'is not and it won't work anywhere else. So the selector isn't CSS and the indexing/filtering isn't JavaScript. Which is why I think it may be convenient but not very useful.Your explanation is faulty.
'.post, .comment' means you want to select all nodes with post class and comment class which is exactly what querySelectorAll does but with some errors but $select() does it correctly.
If you want to select an element with two classes like 'div class='post comment' , you will use '.post.comment'; that is, a tag with both post and comment classes. That is how to use CSS selector.
If your CSS selector query is correct, then it will work in $select(). Maybe you should check CSS documentations for reference.
It seems you're misusing CSS selectors because $select works exactly like querySelectorAll but without its error.
*[something] is meant to work in JavaScript but not in css and standard CSS selectors work as expected. So your concern is not necessary.
Filtering, search and co use JavaScript behind the scenes so they're JavaScript. Everything works well as you would expect them in css or JavaScript.
$select() is designed to work in JavaScript and also works with all standard CSS selectors.
Thanks for the comments.
I think there's a confusion of "and" and "or" terms here.
'.post, .comment' means select all nodes with the "post" class, plus all nodes with the "comment" class". We could phrase this either way in English which makes it a bit tricky to have casual comment threads about it without tripping up.
Are you telling me that is not what you do in querySelectorAll for multiple selectors? querySelectorAll only has some errors but $select() fixes them.
Why do you want to criticize $select() for making what querySelectorAll fail at work well?
I appreciate the willingness to try something new, but the divergence from the CSS selector specification makes this difficult to recommend. It is a new but overlapping DSL with CSS, and it moves a lot of functionality into multi-purpose strings which breaks many core developer experience recommendations:
$('.code').attr('id', 2);you have$select(".code[add|id=2]");This also reduces the ability for tools like IntelliSense and ESLint to provide coding support and improve developer efficiency and accuracy.$selectappears to return an element for a single result likequerySelector. This seems like a bug factory to me. The developer must guarantee the selector count to know the return type, or add logic to test for it, negating the benefit.querySelectorandquerySelectorAllserve different purposes, and this eliminates the developer cues that would tell you which output type to expect. It seems most examples navigate around this by using multiple selections to ensure an array response?It would make more sense to me if
$selectaccepted more arguments. Rather than the comma living inside the "selector" string and serving a different/overloaded purpose than the standard CSS comma, this would provide equivalent functionality and, in my opinion, be more consistent with both CSS and clarity of the destructurable result array. I have three argument selectors passed into the function, so I will get an array of three results back.Thank you for posting your thoughts and ideas. It's interesting to hear other perspectives!
Yes, according to the docs,
$selectreturns a single item, an array of items, or null, depending on matches. UsingquerySelectorAllalways returns a list, so you don't have to check for nulls, and if you convert it to a regular array you can iterate as normal even if the array is empty, which makesquerySelectorAllthe clear winner for me in this particular use case.What will querySelectorAll return if it matches nothing?
How would it work if you use multiple selectors with it? querySelectorAll has a bug and it won't work.
See, check the docs for querySelectorAll, you would realize it is meant to do multiple selections but it doesn't work because it is faulty but $select() fixes it.
Thanks!
It'll always return a NodeList - an empty NodeList if it matched nothing. It has a predictable return type.
Now, you're raising something that is worth checking. That is why I refer people to check the tool first.
I will check this out and see how I can improve the tool with your suggestions.
What are you suggesting would be a predictable return type in this case? And how is this one not predictable depending on your selections?
Remember, you're selecting multiple different thing. So the corresponding response should determine the type that is returned.
You won't select with an #id and expect to return an empty array when nothing is matched.
So, please suggest in your opinion what to return to have consistent type because $select returns consistent types already. Let me understand your suggestions by digging deeper.
Thanks for taking your time.
If something is returning a set of results, I personally prefer that it always does so.
For example, if I search for
.postand there's only one on the page, then withquerySelectorAllI still get a NodeList back, so the same code which works for a multiple results works for a single one. That means I don't have to apply any conditions to check whether it's an object or an array.A lot of systems work the way you've implemented it (I'm looking at APIs in particular) but it adds a step we don't really need.
I don't really like to use
querySelectorbecause I have to do a null check.querySelectorAlldoes the same thing and is consistent. I can then choose to take the first result or check whether the result is empty, and I have the extra info to check whether multiple results were returned when I only expected one.So far as I read,
$selectreturns consistent types (an object for a single match, an array for multiple selectors, an array for multiple matches of a single selector, an array of arrays for a mixture), but since this is dependent on the contents of the DOM at the time, I can't look at the code and know what the return type will be.In particular, if I come to change the selector in the future as part of a theme update or something, I have to use more brain to figure out whether I need to update the code because the variable might change type.
I think if I'd tried to do what you're doing, I'd have made an explicit
destructurableQuerySelectorAllfunction to address the issue you first mentioned without bundling in extra functionality.I'm also rarely, if ever, going to use
#ids in my HTML. I'm going to use classes even if something only appears once, and[data-foo=bar]attributes if their purpose is purely javascript. By nature, these are all things that are legal to repeat in the code, so as far as my code (or a linter) is concerned, the way I process the results will always be the same.So, jQuery but without the established standards or maturity. I don't want to discourage you but this isn't something I'd recommend people adopt. Keep using it and you'll find out why. Happy coding!
Precisely. Once he gets inconsistent results based on the number of nodes returned, he will realize why this is a bad idea. And once he learns SRP, he will know why this breaks it, and badly.
Please show me how I would get inconsistent results. That would be more helpful. I have tried on my own to figure possible issues and I will appreciate it if you point it out in this case.
$select is structured. Please point out how it is not and rest assured I will improve it based on your suggestions and even give your credit for it.
Anyway, I am not scared of learning because I have been learning for several years. Learning is a source of growth.
Okay, let us take this as an example...
Say I have a dynamic view with 0 - n divs.
What does your $select return when there are...
0 found
1 found
more than 1 found
Advise me of that and perhaps I can show you what I am trying to explain. Use 'div' as your selector.
It returns "null" when 0 element is found.
It returns the only found element
It returns an array of all the elements found.
That is it. I am expecting your response.
That is a serious bug, as you now need to run multiple checks against EVERY call to $select to check what it is returning. That scenario REQUIRES querySelectorAll so that you get an expected response type as you don't know from the outset how many you will get. All you need is a function that wraps querySelectoraall and returns an array, which you can then easily deconstruct. That would be two lines of code and 3 lines for core function. Your code would require about 8-9 lines of code for every call to $select. I am sorry, but that is just a beginner mistake.
And that doesn't include your breakage of the single responsibility principle by allowing deletion in a function that is meant for selection. And changing the selector syntax too. If CSS changed to include that syntax, your code would cease to work.
If you want to see code samples that would vastly improve your code, then I will happily supply them.
Also, what bug is in querySelectorAll or querySelector? I have never found a bug in either. Please elaborate on this "bug".
This seems like a skill issue, a lack of understand of Javascript and best practices.
If you want people to use your stuff, maybe you should actually engage with their objections and questions instead of just telling them that they're wrong and they should go use your stuff.
Skill issue, what? Scratch that! People can object based on biases without using a tool and that is okay.
Our argument will be more reasonable if they have a balance view of the tool first. Arguing without understanding how a thing works is unnecessary.
For example, they said reusability but the tool is reusable. It returns elements they can manipulate further but how would they know without using the tool? That is why I said they should check it out and come back to have a discussion after that.
I noticed a person that checked it now has to raise opinions that are not correct judging from general standard after realizing the tool actually works.
Even when they have genuine concern, it is inaccurate without using the tool.
Another thing is they said single responsibility — are they referring to $select or the query passed to it?
Each part of the query does a thing which you can easily reason with — $select() is just a processor and does a thing by processing queries. Just like you won't expect a JavaScript engine to not process several functions, you won't expect a query engine not to process several queries.
But each part of every query does a thing too.
And for your information, there is no best practice, we only have practices that worked for some people in their codebases and they tried to generalize them.
Let me say this again, go check it out and you will understand why I direct people to check it out before arguing with them.
Thanks
Even if they're wrong, you're asking people to invest their time on your stuff and you can't even do the bare minimum of engaging with them in good faith.
That's is the definition of best practice.
It's seems you're not open to new information. I doubt you'll achieve your aim with your attitude here. Maybe some engagement on this article, if that's your goal.
First, I am referring people to check it out out of good faith not to waste their time arguing on things they don't know yet
It is like me arguing with people living in New York city after showing me a picture of it. How realistic will my opinion be without visiting New York city?
Yes, they raised their cases but the cases are exactly what the tool does and I told them the tool does what they raised and direct them to check it for confirmation.
And people are now raising good concerns.
Let's leave best practices aside because that is another unending argument.
I hope you understand my view now?
And people are actually checking it and now raising genuine cases which they couldn't have raised without checking the tool.
I get your points anyway. Thanks!
So just jQuery but with a weird syntax to delete or modify items.
Cool.
It is more than that. You will love the syntax. Just try it out.
hard pass
In larger projects your
$selectwill become far less appealing and would even introduce more inconsistencies in the code.There's a reason why there's
querySelectorandquerySelectorAll: It's because both functions return a different type.querySelectoralways returnsNode | nullwhereasquerySelectorAllalways returnsNodeList. Regardless of the of the input. This is a good thing because you, as a programmer, do not need to check whether your query returnsnull, aNodeor aNodeList. Having two separate functions eliminates the guesswork.querySelectorandquerySelectorAlldon't just live indocument. Rather, they're methods ofElement. Meaning you can call these functions on other DOM elements as well, allowing you to query only in specific sub-sections of the DOM. This is excellent for performance reasons, as the browser won't have to go through the entire document for every query. It also means I can pass my queriedElements to other functions who can then perform subsequent queries.I believe
$selectdoes not support something similar?The queries we write in
querySelectorandquerySelectorAllfollow the selectors syntax from the CSS spec. The fun thing about CSS? Counting starts at 1. Whereas your$selectfunction allows for JS array syntax ([0]) which starts counting at 0. You now cause inconsistencies by combining two different cultures into one:If people are so bothered by writing the long
queryBlahblahmethod names, never want aNodeListand are hypnotised by the idea of destructuring, then I've got 11 lines of code to ease their mind:(I do not condone this code, btw)
Sorry for the dogpiling :)
The issue of consistent type can easily be adjusted in $select if that is better. Why would you prefer return type of array instead of Null when nothing is found?
You can also used querySelectorAll on elements selected with $select. It just that there is no reason to do so as you can select the nested elements together.
$select caches the DOM, so it doesn't hit the DOM every second.
.post[1] is meant to simulate what querySelectorAll does but not css. If you want to select by using css, just use css and it works.
$select is more useful for composition. You can easily use it in a component.
Thanks! Anyway, I will look into what you said to see how to use your suggestions to improve the library.
Well done my brother. Keep it up, don't let tech bros talk you down. These are same tech bros who said tailwind isn't going anywhere but today it's all history. Keep pushing for people to try it, when they try it they might start using. Carry go my brother. NB: Best of luck. If there is any constructive criticism, take it onboard and improve your tool. Forget about the nay sayer
Thank you for the support and inspiration.
I really appreciate it. Thanks!
I didn't even think about that before. But when I was looking for an element or a bunch of elements to select, I can always add a class. But I see the whole point here. I'll save lots of structuring works and there is less work to do.
Now, you get the point.
Okay. If I'm not wrong you just head butter into a DSA strings lesson and jumped right into developing a library that "YOU" think is buggy.
Let's say you are right. And somehow I installed $select. Let's compare syntaxes.
// I need to add class foo in only the first instance and bar in the others
So what exactly are you solving here? Now your response will be goading me in to trying out your library and set the classes using strings, but now I want to log the string values of the elements. Do I run another select query? Yes I would have to. And I hate repeating code, be it of any kind
Your code is not accurate because you can use the same function you used with querySelectorAll with the returned values of $select. It is querySelectorAll on steroids.
What you would have done is below after first filtering for what you want:
Now, you see the difference ✅
And what exactly is the return value? A
Node? ANode[]?null?How will you infer the return type? Be it for TypeScript, linters or IntelliSense (or similar tools). Whatever the case may be, you'll get what all of us are trying to say once you actually get to programming real things.
What are you saying that I haven't experienced in my 12+ years of programming please?
It seems you don't even understand what is happening here.
When you select a group of elements, you're automatically expecting a node list [ ]. Nothing is hidden about it.
You will certainly get what is expected. Hope you now understand it returns correct values?
Your selector determines what is returned.
Now, it seems you don't get what others complain about. They're worried it shouldn't return Null when nothing is found for a group selection and that it should return an empty array instead of Null.
Even it is not much of a problem when it returns null, it just that it is safer to make sure it returns an empty array when nothing is found for a group selection so that we will just iterate over it without null check and I have already fix it for korasjs@v.0.0.3.
That has nothing to do with your case here.
So
$select(".post")returns and array instead of a null value?What if I want a single element? The current assumption need for me to check if it's an array and it's empty instead of just checking if it's null. If you think this is a valid solution then the 12 years is too less.
And the fact that you couldn't understand my reference, adds to it.
Why will it return a null when an array of elements is found?
It currently returns Null if a single element is not found.
It also currently returns Null if an array of elements is not found but people are saying it should return an empty array in this case.
What do you think?
No, you won't check for anything if a single element is returned. If a single element is found, it will return a single element. That is not a problem.
You're saying this because you didn't take your time to actually test the tool to be sure of how it works so that you can have factual claims.
It works exactly like you expect. Just try it out and see if it is or not, then you will have factual claims instead of opinions.
I hope you get the point now.
Oh, so you wrote another partial jQuery clone. Sorry to bust your bubble, but this is 2025 and we have modern frontend frameworks (react, angular, vue, svelte, solid, astro) to render DOM and keep its references so we only ever have to manually query dom nodes for our initial render target - and we can use getElementById for that.
My friend, thanks for bursting my bubble but now, let me also burst your bubble.
You can't use all of the frameworks you mentioned without a transpiler, compiler, virtual DOM or tagged templates.
Now, koras.jsx — $select and $render — makes it possible to use JSX in browsers and servers without a virtual DOM or tagged templates.
While that is not entirely true, the other solutions are far less convenient. But even then, what is the issue with that? What should stop me from using these solutions?
What you have there is not JSX. It is just HTML template strings that look like lit-html in poor light and a renderer that re-renders already rendered components. But we do not re-render full components if not necessary in modern frameworks for a reason. If you test your library in the frontend framework benchmark, you'll see why I'm less than excited about that idea.
Have you benched marked it? Do so maybe you will reconsider your opinion once again.
Thank you for the insight. I will look into everything to see if there is anything I can use to improve the project.
And remember, none of the frameworks you mentioned can comfortably work on both browsers and servers at the same time without a lot of issues. Don't even mention React because I built the project so that my students could easily learn composition and best React practices from js before moving to React.
I'm not here to do your work for you. I have superficially read through your code and I see no way your framework can even remotely compete with the faster frameworks.
That's what their related metaframeworks (next, nuxt, svelte-kit, solid-start) are for. Do your research before you make your claims, please.
Why do you assume I have not done my research? See, you are currently criticising the fastest UI framework ever created by man.
Cheers!
const [posts, comments] = $select('.post, .comment');This is terrible. This should have been an array of
posts or commentsbut instead you get 2 different lists.This maybe one of the worst api's I've actually seen. If I wanted two different lists, I would make two different calls.
I am guessing whoever came up with this api had a single niche idea in their head and has made a super short sighted decision because of it.
I know your opinion is genuine.
Why should it have been an array of posts or comments but not posts and comments aside from the fact that it is in the MDN docs?
Because you are now going against CSS syntax, it would be like calling all your other method names French.
Could you imagen all arrays in JS being
.map(), .filter(), forEach()but your one API it would be.carte(), .filtre(), .pourChacum()And your only response would beread the Docsorget gud.Going against the grain will cause frustration. One of the problems jQuery had was also going against the grain with argument order.
array.forEach(item, index, arrayInstance)vsjQueryArray.each(index, item)So no method reuse was possible unless you wanted to do argument integrations.As for
forEachbeing the only method that works, and notfilterormap, you may wish to look again, since we now have Iterator helpers, which gives us the additional methods of.drop(),.take(),.flatMap(),.some(),.every(),.find()and I am sure there are more , we have all the methods at our disposal.querySelectorAll()is a lazy list, so it only gets the next value when it's required, and forgets the items it's already processed. So the memory footprint forNodeListfromquerySelectorAll()is miniscule, especially if used against hundreds of thousands of dom elements. (Though, as you may guess, the browser would be starting to struggle by that point also). But it's designed to work at scale instead of only working for small lists of a hundred or so.I will definitely use everything you said to improve this but please use querySelectorAll to select multiple instances of posts and comments ('.post, .comment') and see what happens, then you will also understand my point too.
Please try it.
Tried it, and it works perfectly.

Exactly as I want it to happen. And as you can see they are in the correct order from the numbers.
Please how will you destructure the result you get into [posts, comments]
Please educate me!
Until you know that the underlying method contains
document.querySelectorAll()as well. Adocument.querySelectorAll()with added complexity.Oowww… that’s hurt!
Then? Is that not how all other tools are built?
See, querySelectorAll has some bugs fixed by $select() and makes manipulating the DOM fun and comfortable.
That is why it is important and needed.
IMO, even the oldest jQuery is better because it does not require me to learn new CSS syntax as in the
$select()argument.Yes it simplify things, but before users are able to use the tool it requires them not only to learn the JavaScript part but also to learn that added-complexity CSS selector. That’s a double tasks:
$select()function.No. Even if you have to learn it, you learn it at a glance because it uses what you already know.
Once you understand CSS selectors and querySelectorAll, you already know how to use $select.
I'm sorry, but this entire post reads like an ad for your library - especially when combined with your un-argumented "you're wrong, go try it" responses to legitimate comments
No, it is not. It is a way of sharing ideas with like-minded people and learn from them.
I either pointed out the fault in people's arguments or let them know the tool already solved the issue they raised.
I did so for us to have genuine argument for everyone to pick one or two things.
It is done in good faith but not ads. Thanks for the view.
The title of this article suggests a bit that there's something wrong with querySelector, and that's why you're not using it anymore (and we shouldn't either) ...
That's not really the case IMO - the point is you've developed a little utility lib which you like using, and you prefer using that now instead of querySelector ...
That's fine of course, and it's also fine that you share the lib that you developed, but I feel that the title of the article is a little bit clickbait-y ;-)
P.S. I rarely use querySelector either - sometimes I use jQuery, in other cases I use React or Vue, or another framework where there's no need for direct DOM manipulation.
No, I didn't intend to drive clicks; something is actually wrong with it. It has some bugs that are fixed in $select plus the other cases I raised.
And by the time you use $select, you will practically and emotionally relate with my claim.
P.S: If you use React or Vue, you might like $select and its friend $render because they make it possible to use JSX in browsers and servers without a virtual DOM or tagged templates.
Seems that a large part of the commenters doesn't agree with your take that querySelector has "bugs", but okay ;-)
If you developed a handy utility lib and want to share it with us, great, but the way you present it still comes across a bit as click bait ... but hey never mind, as I said I'm using jQuery or React/Vue and rarely querySelector, so I don't really have skin in this game ... anyway, thanks for the effort, have a nice day!
I'll always support a developer's right to build something new, but it seems you've just reinvented jQuery but with a more opaque, less extensible, string-based API which will lack any tooling or IDE support.
Consider:
If you haven't already, take a look at jQuery's universal selector function
$(), the Sizzle library that powers it, it's internal collection (effectively all selections are converted to internal arrays), chaining, filtering (the equivalent of your DSL), and all other functionality (traversal, events, etc) which are effectively plugins on the core code.Also, check out libraries like Zepto, Cash and Umbrella JS which attempt to be more lightweight versions, yet still extensible.
And, bear in mind that jQuery was released nearly 20 years ago; amazing, really!
I like your argument but $select is extensible by composition because you
can build whatever you want on the elements it returns and it is still smaller and with more useful features than all the tools you mentioned above.
Look, the creator of jQuery is a legend to me as he influenced my skills through his writing so no disrespect.
I think this simplifies how to target DOM using JS and avoids repetition. Using $select() going forward.
I appreciate the "see a problem, fix a problem" gusto you're showing here; but there are several fundamental architectural issues with the library you're proposing.
** You're inappropriately mixing concerns. A query function should not have built-in capabilities to perform updates. "Select" is a well-known and well-understood term in computer science, and your library takes the knowledge that every single potential user of your library has and turns it into a trap. Select is understood to be and therefore should be a read-only operation, full stop.
**You're building a bespoke domain language where it's not appropriate. None of what you're trying to achieve by adding
add,remove, anddeleteinto the string is done better than it would be by Javascript code itself; and in trying to reimplement the wheel you've ended up with an ill-defined syntax. How would I use$selectto, say, add anidoffoo]barto an element?Adding a bespoke domain language also hinders the ability of tools like TypeScript to syntax check code at compile-time. Which can be worth the headaches that creates if the language you're creating adds value over just using plain old Javascript; but it doesn't here.
I'll also throw in the forward-compatibility problem in that you don't own the CSS selector syntax and so trying to extend it from within is inherently fraught with danger. If some day it evolves to allow
div[remove|id]as a valid selector (say, by adding the|character as an operator to attribute selector syntax to say "give me nodes that have either of these attributes"), then you become in conflict with the ecosystem you're trying live on with no clear path out.** You're inconsistent in your interface. Your
$selectmethod currently returns one of three disjoint return types (null, element, array) based on both the string passed to it and the state of the DOM tree being queried; and that 1) prevents any sort of reasonable strong typing by tools like TypeScript, and 2) requires developers to type-check the result of$selectevery time.I understand the desire for a more fluent interface for working with the DOM, but your approach here is fundamentally flawed in concept and is solving problems that frankly don't really exist. Going down your list of "features":
Need an element from a selector by index?
Need to delete elements?
Need to add/remove/modify attributes on elements?
Want a destructured array of NodeLists for several different selectors without having to repeatedly mention document.querySelectorAll?
Want to use normal array methods?
Want to "ship less Javascript?"
Need to "disable superpowers?"
You still don't understand separation of concern yet. I need to write about this because many people assume Separation of Concerns is all about not mixing structures, styles and behaviour.
Every piece of code violates separation of concerns because concerns are relative to problems your solve, the people you're solving it for and the person solving it.
And I will show you examples in this response. Just keep reading.
You're worried everyone already associates "select" with something but you forget we use "$select" in this case to indicate its difference.
And don't forget, $select is a query engine that only processes queries but nothing else. You can't extend its arguments too.
My first question is "have you tried it and do you get all the errors you said in typescript?". If yes, tell me the errors and I will fix them.
I don't understand what you meant by foo]bar. Clarify your intent and will definitely give better solutions that you can't ever get with pure JavaScript.
In understand system design so $select is designed to no use its own operations once a query doesn't match its query. So any change in css queries is catered for.
In case CSS adopts div[remove|id], $select will still work because that is a $select query though we can ship another version of the library to use css alternative. So, that is not a problem because no error would be caused.
Please, don't assume I also didn't worry about everything you're worried about why building the tool. I am also a developer who has similar concerns like you do so I always put in efforts in this regard.
[audio, posts] = $select('#audio, .post');
The only inconsistent thing you can mention is for group selection which should return an empty array when nothing is found so that people won't worry about a case of null and I have adjusted the code here and will be shipped in korasjs@0.0.3
But the rest work as they should.
Your example code are violating my separation of concerns. First, people can easily extend the functions you provided — their arguments and everything about them if it is comfortable to achieve what they want, right? It violate my concern because I don't want to give them that chance. $select should only be extended by composition. You can only extend its returned values.
Your functions hit the DOM every time they're used, meaning I might be forced to extend it. They're also violating another concern.
The alternative your provide means people need to write functions for almost all the attributes we have in html and once you automate them; you're reinventing $select.
You code also violates another concern.
Please, separation of concerns is a relative term. What you're concerned about in a project is different from what you're concerned about in another project. So people should stop assuming is all about separating structures, styles and behaviour.
And before you think I don't understand separation of concerns, think again, it is an adaptation of separation of powers and I have my background in Art.
An article coming on it soon!
I'm not entirely convinced this isn't an elaborate troll.
I feel like creating a library to replace these functions is over kill.
It is okay to feel that way but when you consider the repetitive functions you would write to achieve the same purpose and every other things; you will realize $select is a better option especially for composition and you can use it directly in html with events like onclick etc.
I want you to know $select is an accessory for composition to be used in a component.
Koras.jsx is meant to make JSX possible in browsers and servers without tagged templates or a virtual DOM. When $select is used in a component, it becomes more useful.
That is why I direct people to the docs so that they can experience it first hand.
Well put. Thank you for your explanation. Although I have other more precise and custom methods for achieving this, it seems you have came up with the way you find efficient.
Nice workaround. Congratulations! Destructuration is the most powerful feature.
Thank you!
Great job on creating something new. I have found it slightly annoying that querySelector and QuerySelectorAll had slightly different returns — not so annoyed I felt the need to create a library for it — but I like the intent.
the DOM destructuring is especially interesting. How would it work if I selected based on attributes (
[data-article]), elements (article) or compound selectors (#main h1.article)?I'm not sure that I like the idea of adding arguments into the function for doing operations. (e.g.
$select('.post[remove|class=hidden]');That seems like it's a conflation of roles.I would think it'd be more useful to either pass an "operation" argument :
or add a method that could do it:
Those of us that remember the jQuery days probably would prefer the latter.
Putting a remove operation inside of the select argument means that we'd constantly be writing template literals.
I am curious, too, if the operations are commutative. In other words, are these two the same?
This is where I think it might be easier if these were chainable methods:
I'm also curious how I'd select elements by the attribute selector if the square brackets are also used for operations. Would this be a problem?
Regardless of my thoughts, I think it's cool that you recognized a problem you were having in your developer experience and created a solution for it. Good job.
Honestly, you points force me to think more.
I need to look further into the "operation argument" you mentioned.
Thank you!
Honestly I think the best approach is a chainable method, rather than an "operation argument", because then it's extremely clear to any developers what's happening.
But what you could do, internally is have the "operation argument" or a chainable method both reference the same functionality.
Having a generic
.remove()method where I could pass in an object with any attributes I wanted, and have them all removed at once, has a big appeal:Thank you. I will consider everything to improve the library.
This seems like something cool to use... but completely disposable. At least for the purpose that the author of the article proposed.
It will never, ever, be better to use a library for something that you solve, natively, with just a few, or one, lines. At the very least, you will be adding and becoming hostage to something external, which could cease to exist overnight.
So, the idea is cool, but saying that this replaces the native method, or simplifies it just because it 'writes less', that's wrong, just the main code of the library is 1500 lines. Just because I don't see it, does that mean it's smaller?
Concern is solid but truth the code for $select is about 100 lines of code and $render uses the rest because it makes it possible to use JSX in browsers and servers without a virtual DOM or tagged templates.
So, it is not 1450+ code.
I combined $select and $render because they work best together for better composition.
And you did a great job, actually, better than I would have done.
However, I think you were wrong to "sell" the idea as just a replacement for query.selector, your tool does more than that.
But in a one-for-one context, using the native tool is more advantageous, at least for the specific case of your article.
Maybe if you try to put it another way, acceptance would be better.
Why are you introduce an issue that has never been one before mate? Do you know what reasons drives me away from jquery? One of them is your
$select(). It messes up the plural system of English and without proper doc, it is even more confused. Now you bring back a similar problem... queryselector is good mate.It is okay to act on your biases but it is better to be curious in case something is different.
$select is more than that because it makes it possible to use composition like in React in browsers and servers with only vanilla JavaScript.
Can you do that with querySelectorAll or jQuery? Nah!
This is completely unnecessary and "solves" a problem that doesn't exist. Maybe just stop using querySelector since that's the actual issue you've cited. If you need one element, use getElementById. If you need multiple elements, use querySelectorAll. Easy.
This a non-existent issue. Both querySelector and querySelectorAll have different meanings for a reason, which is why they are separate methods. If you want to unify, just use querySelectorAll, convert to an array aand destructure the result, then you can encapsulate that if you wish. It is not rocket surgery.
It solves a problem. It makes it easy and possible to use JSX without a virtual DOM and tagged templates especially in a component in browsers and servers which querySelectorAll can't do.
It is only by using it one can realize how useful it is.
That is not what your article is about though. You said you would never use querySelector or querySelectorAll again, and proposed that to others. In a vanilla JS project, not using JSX, then your proposed alternative is not only overkill, but would also be a serious code smell.
Where I work, we have two core functions $ and $$ (not jQuery), that wrap querySelector and querySelectorAll, which take the selector as an argument (with an optional root as the 2nd parameter, defaults to document). So, our code is way shorter than your sample, but only has the overhead of two small core wrapper functions, not a lib that is intended for a whole other purpose (JSX).
If it is a great lib for JSX, then you should have led with that, not the false claim in your article. If you choose this lib over querySelectorAll for every project in future, then you are making a serious mistake, I assure you. So, you are either very misguided, or merely trying to market this lib for some reason.
It seems we are getting onto the same page.
I shared my view after using querySelectorAll and querySelector for many years and compared it with $select but most people here led with their biases without checking $select to know how it works to have a balance view or counter.
I wrote the article based on my experience using querySelectorAll, querySelector and $select() and that means I understand the cases you raised but how do you understand the reasons for my claims without experiencing the solution I provided?
$select, even in isolation, is still better than using querySelectorAll or querySelector in any non-toy projects.
That is my stand.
I don't see how it handles attribute selectors, and why the operations are not further arguments instead of something that looks like an attribute selector.
The other thing is, that I did not see any unit tests for the said
$selectand without that, you cannot say it does everything thatquerySelectorAlldoes.Let me start with unit test.
The unit test is coming soon because I had to prioritize getting it done first as the problem I solved — using JSX without a virtual DOM or tagged templates in browsers and servers — is generally considered impossible by frontend/js engineers.
And it is impossible to write unit test for what no one, including myself, understood. So I had to focus on understanding it and finding a way to solve the problem first.
Now that the problem is solved, I will work on the unit test.
For how it handles attribute selectors, check the picture attached which is from the docs.
I have considered everything before bringing it to the public but if you find any error, please let me know.
The operations are not further arguments because you might need to put each argument in a string and we developers tend to not like strings in such a case.
If you have a way to use them as further arguments without passing all of them as strings, please let me know.
This article is interesting.
I would never hate on a programmer who took time to work on this kind of project. Especially not a Nigerian, God forbid. It takes a lot to put something it in the world (with docs!), and I really hope you grow and become better in your craft.
But Google put this article in my home tab, and I can't not comment on hubris.
Your library has an
index.jsfile that is 1492 lines long. That is not less JavaScript. With one function:I would already have 75% of its functionality.
Is there a reason you cant do:
It's not that much longer, if the character count is that important.
I could make the argument that your library would introduce more bugs, but eh.
Again, you can just do
element.append(...arrayGeneratedBy$Select). This is nitpicky, but it is the main issue I have with this post. You are presenting features that were agreed on by specification authors as "bugs" and pushing your library as a solution to a problem that does not exist. If anybody is working with DOM nodes directly, they are either doing it because they really want to, in which case a library would just irritate them, or they are already using jQuery.You made custom versions of
setAttribute,filter,sort, andjsonStringifyin JavaScript. In what world would these ever be as efficient as the C++ running in v8? I call bs in the "one millisecond" claim.Another thing, I don't like the name.
$select()can retrieve elements from the DOM, but it can also delete elements or mutate elements to add/remove attributes. That's not a selection. At leastquerySelectorandquerySelectorAlldo one thing each.I went through the library, and I have several more issues, but they are related to the framework implementation and therefore completely irrelevant to this post.
I don't know if this is click-bait/rage-bait, or you genuinely think you've created something mind-blowing. Either way. I regret to inform you that you have not.
This does give a different result than
$selectwould, actually. In$selectit would be 3 different queries, resulting in 3 separate arrays (or elements). YourquerySelectorAllcombines everything into a single array, without any guarantees of order. If an element with the.postclass preceded the element with id#audioin the DOM it'd be assigned to theaudioconstant, for instance.It would be better to raise the issues you saw. It might help in making the project better so please don't hold back.
For your information, I am a proud Nigerian.
Now, let me address your opinions.
It is actually mind-blowing if you pay attention and not judge based on your assumptions and experience which is relative to you or try to use the tool before raising any issue.
koras.js makes it possible to use JSX like in React with only vanilla JavaScript without a virtual DOM or tagged templates which is generally considered impossible by every js engineer — isn't that mind-blowing?
And consider I was able to solve the problem using a mathematical formula nth = a + (n - 1)d and ask again "Isn't that mind-blowing?". I digressed.
So, it solves a problem most library solve in hundreds of thousands of lines of code in less than 1450 lines. Don't assume the library only does DOM selections — have you even checked the docs?
Your claim that 1450+ lines of code is for $select is inaccurate. It takes less than 100 lines.
Now, if you try to workaround the issues $select solves, you will end up having bloated code by the time you write 1000 lines of code. If you want to understand my claim practically and emotionally, kindly use the project then you would have a different opinion. Certainly.
I have been using the workaround you raised for years and that is why I could provide a better solution. To really understand my case, please leave your biases aside and use the thing.
Also, $select comes with a lot of operations you will need to repeat when you use querySelectorAll but with $select, you only need a line of code in many cases.
You said you didn't like the name because it seems to do many things but that is not accurate.
$select is a query processor and all it does is process queries. It does a thing. The queries you pass to it are the ones that delete, filter and co. and you need to specify them.
You said I made my custom jsonStringify(). Do you know why? It is because JSON.stringify() has some issues so don't let me go into more details about that. That is it.
Thanks!
In the jQuery/Prototype heyday we were used to writing
$('.posts')and do all sorts of things with the result. I think $select commits the same mistake as the jQuery function.const header = $select('#header')versusconst header = document.querySelector('#header')With the $select function you are missing the information that the code wants a single element.
You can make a static analysis rule to check that an id selector has to use the querySelector method, or even better use the getElementById method. Making the intention of the code as specific as possible, improves the readability.
That is not possible with the $select function, because it is too generic.
While
$select('.post[delete|i=2]');might look readable, it is not clear what the result is.If I read the code correct, it returns the removed elements. With the name select I would expect the return to be the elements without the deleted element(s). I'm not saying the return of the function is wrong, I can see a case for both returns. It just makes the result opaque.
$delete('.post', 'i=2')causes less confusion, in my opinion. But then is it that hard to writedocument.querySelector('.post:nth-child(2)').remove()?With the element and attribute actions the order of the actions is important.
$select('.post[delete|i=2][add|class=hidden]');and$select('.post[add|class=hidden][delete|i=2]');While you get the same return, the second example does a lot more manipulations.
Because the code that does the actions is hidden, it is harder to identify if it going to be a problem or not.
I also think the action names are too generic, like delete and remove. Because they are synonyms people are going to confuse those. Or even wonder why there are two actions with a similar name.
I looked at the code, and I see you put a lot of effort in it. The pursuit to write less code is good.
I think that single focus brought the code to a place where the negatives outweigh the positives.
I don't get it.
How is
document.querySelector()anddocument.querySelectorAll()sticking to the distant past while missing many juicy features in Javascript?The library you suggest just in turn uses
document.querySelector()anddocument.querySelectorAll()I’m not sure why I would want to learn how to use some seemingly hacky tool to do what’s natural in JavaScript already. Looks to me like you would have been better served to not jam everything into
$selectand instead make distinct functions so that it’s clear, you’ve lost a lot of people on that. You also don’t do yourself any favors by presenting your solution and basically make everyone feel stupid for dismissing it on the contexts that they don’t have issues withquerySelector/Allor they don’t like how it’s difficult to read what’s happening in your$selectalternative. I don’t think you were ready for people to disagree because you spent time solving something for your use case and couldn’t possibly imagine how someone else might not find it useful.If someone's merge request added a library because they didn't like querySelector they'd be laughed out of code review anywhere I've worked
It looks like you don't work with modules, because if you do and you do it on the right way, there aren't any issues with that.
The way I do it:
I work with modules but $select does more than what you said above.
You need a line of code to fitler a table and co. in $select. A lot of burden is lifted.
I think you omitted one important line when writing your library and this post:
import { humility } from "./basic-human-traits";
Oh, please let me learn why you said that. And if it requires direct messages, I am comfortable either ways.
Thank you.
I don't want to be too harsh since clearly you've gotten plenty of criticism (though most of it seems reasonable to me). It's good to build something and put it out there. That said, I personally wouldn't use this because I don't like the idea of putting such power into potentially long and complicated strings. Seems like the kind of thing that would eventually lead to string manipulation being needed, which I'd rather avoid if possible.
Why do you assume string manipulation would be needed?
It is obvious you opinion is based on your biases other than curiosity.
If you had checked the tools, you would have had a balance view.
What I am missing here is performance analysis (including increased memory pressure from the additional allocations from temp arrays and string splits).
If I am making a compromise (which this is), I want to know what I am trading (in addition to the added complexity of "stringly" typed language, additional external dependency, learning curve, ...).
I think that there is a lot of melodrama here.
querySelector and querySelectorAll are well documented and easy to use.
Not sure I get your point.
And you miss something as well.
Here's a sample piece of code.
div[id="${divId}"]let divId = rec.data.divId;
let query =
;
let el = cmp.el.select(query);
if(el && el.elements && el.elements.length) {
el = el.elements[0];
let layoutEl = el.querySelector("div.engine-widget-wrap-layout");
if(layoutEl) {
el.classList[method]("engine-widget-wrap-layout-over");
}
}
In the above code, you can see how querySelector can be used at the element level, not just the document level.
Suffice to say, the fastest mean of retrieval is always the getElementById, but when you are creating components and using CSS as a means of identifying 'relative' elements, then querySelector is a good choice.
And who says you can't leverage deconstruction?
[one, two, three] = [... el.querySelectorAll("div")]The above works, if you expect 3 items, then you shall see the first 3 items deconstructed into the variables listed to the left.
And you mention $select() as a function, but where is it?
Is it something you wrote? or part of a lib? I mean, one could assume it's jQuery, but jQuery has implicit DOM selector functionality in many of its methods.
Suffice to say, I feel like your whining is much ado about nothing.
It is really nice, that you are creative and even made your own selector language. I like to make such things too.
But let me say a few notes on consistency, as I'm one who have seen big projects.
1) It seems inconsistent to use 'post[delete', because you are trying to delete dom-representation-of-post. But you really want to delete post itself, and keep the representation in sync automatically.
2) TS and IDE can help a lot in finding bugs. But they does not understand your great new selector language. $select can return any type, and they can not help.
Thanks. The case of type is something straight forward to address. $select type is consistent.
It only return null when a group of elements are not found. That is the only time you want an empty node list and that is so easy to fix.
I will work on it. Thanks.
const [posts, comments] = [$all(".post"), $all(".comment")]
Nonsense!
This would be way less annoying if you were just transparent about plugging this library you wrote instead of using a click bait title that implies QuerySelectors are useless
Yeah, it is useless when you start using $select.
What if I wanted to chain selectors
Why would you do that when you can destructure them and apply the operations you want in the query?
You chain selectors because you can only work on a element at a time.
With $select, you can select every elements you want at once and still apply some operations to them.
For example,
const [posts, postImgs] = $select('.post[add|class=bounce], .post>img[add|style= 1px solid blue]');
The experience of using select is much better.
Nice ad disguised as critique on vanilla JS.
Is there a library called jQuery?
This is not jQuery in operations.
Well, that was funny but it isn't April yet 🤔😂
Congrat you ve just reinvented Jquery
It is more than jQuery. It gives JSX without using a virtual DOM or tagged templates.
Yeah! Honestly, my programming skill was influenced by John Resig because I learned from his book years ago.
Smells dangerously like code golfing.
Over the last twenty years in front-end I have accumulated sufficient trauma inflicted by those who think writing code is all a software engineer does.
Over the past 13 years, I have learned many developers assume there is monopoly of experience and understanding.
I don't think
Someone like me would like to pull a whole library I prolly won't make use of rather than selecting.
Mxm
Learnt from this and Thanks for sharing
I understand you're making this judgement without checking out the actual tool.
And that is okay but this is a project you will definitely love to use if you check it out.