tl;dr When browsers start to adapt proposals from Open UI, it might not be necessary to use any 3rd party libraries to have nice components and controls in web applications e.g. selects. It would require only a minimum of CSS and Javascript to get them working and looking good.
The purpose of the Open UI, a W3C Community Group, is to allow web developers to style and extend built-in web UI components and controls, such as dropdowns, checkboxes, radio buttons, and date/color pickers.
To do that, we’ll need to fully specify ...
We no longer use non-deterministic versions like lts/gallium
. This is not supported by all tools. In particular asdf is sunsetting its support for LTS aliases.
You can chain multiple Capybara matchers on the page
or any element:
expect(page)
.to have_content('Example Course')
.and have_css('.course.active')
.and have_button('Start')
When you chain multiple matchers using and
, [Capybara will retry the entire chain](https://github.com/teamcapybara/capybara/blob/c0cbf4024c1abd48b0c22c2930e7b05af58ab284/lib/capybara/rspec/matc...
A common cause of non-accessible web pages are elements that were made interactive via JavaScript but cannot be focused or activated with anything but the mouse.
Let's take a look at a common example:
<form filter>
<input filter--query name="query" type="text">
<span filter--reset>Clear Search</span>
</form>
The HTML above is being activated with an Unpoly compiler like this:
up.compiler('[filter]', function(filterForm) {
const resetButton = filterForm.querySelec...
I recently built a screen with a very high and wide table in the center. This posed some challenges:
What I ended up doing is reusing the horizontal page scrollbar (which is naturally fixed at t...
The Web Animations API has great browser support, and you should be using it to animate DOM elements from JavaScript, or to control or wait for CSS animations.
Here is a quick overview of a few useful features:
Use the Element#animate() function to perform animations on an element.
Its API probably a bit different from how your...
All browsers implement an event named beforeunload. It is fired when the active window is closed and can be used to display an alert to warn the user about unsaved changes.
To trigger the alert, you have to call preventDefault()
on the event.
Note
The
beforeunload
event is only dispatched when the user navigation makes a full page load, or if it closes the tab entirely. It will not be dispatched when navigating via JavaScript. In this case you need to ...
Up until Chrome 120, scrollbars could only be styled using the various -webkit-scrollbar-*
pseudo elements, e.g. to make the scrollbars have no arrows, be rounded, or with additional margin towards their container.
Starting with version 121, Chrome now also supports the spec-compliant properties scrollbar-width
and scrollbar-color
.
These allow less styling. You may only specify the track and thumb colors, and a non-specific width like auto
, thin
, or none
.
Any form fields where users enter numbers should be an <input type="number">
.
Numeric inputs have several benefits over <input type="text">
:
1,23
for <input type="number" value="1.23">
."1.23"
eve...tl;dr
We recommend configuring Selenium's unhandled prompt behavior to "ignore".
When running tests in a real browser, we use Selenium. Each browser is controlled by a specific driver, e.g. Selenium::WebDriver::Chrome
for Chrome.
There is one quirk to all drivers (at least those following the W3C webdriver spec) that can be impractical:
When any user prompt (like an alert
) is encountered when trying to perform an action, they will [dismiss the dialog by default](https://w3c....
Multiply by 1x the unit:
$number = 13
$length = $number * 1px // => 13px
Divide by 1x the unit:
$length = 13px
$number = $length / 1px // => 13
the result of an addition or subtraction between two numbers of different units is expressed in the first member’s unit
Thus, to convert a number, add it to 0 of the desired unit:
$duration: .21s
$duration-in-milliseconds: 0ms + $duration // => 210ms
An example is storing a transition duration as CS...
Getting CSS (and JS) live reloading to work in a esbuild / Rails project is a bit of a hassle, but the following seems to work decently well.
We assume that you already use a standard "esbuild in Rails" setup, and have an esbuild watcher running that picks up your source code in app/assets
and compiles to public/assets
; if not change the paths below accordingly.
We will
guard-livereload
gem as the livereload server (which send updates to the browser),livereload-js
npm package in the browser to con...Make sure that you use the correct property when editing an HTML attribute. Using innerHTML
with unsafe arguments makes your application vulnerable to XSS.
textContent
: Sets the content of a Node
(arguments are HTML-safe escaped)innerHTML
: Sets the HTML of an Element
(arguments are not escaped and may not contain user content)This hierarchy gives you a better understanding, where the textContent
and the innerHTML
properties are defined. It also includes (just for completeness) the innerText
property, whi...
Every modern Rails app should have a Content Security Policy enabled.
The following "default" is a minimal policy that should
In your config/initializers/content_security_policy.rb
, set
Rails.application.config.content_security_policy do |policy|
policy.object_src :none
policy.script_src :unsafe_eval, :strict_dynamic, :https # Browsers with support for "'strict-dynamic'" will ignore "https:"
po...
Chromedriver (or selenium-webdriver?) will not reliably scroll elements into view before clicking them, and actually not click the element because of that.
We've seen this happen for elements which are just barely in the viewport (e.g. the upper 2px of a 40px button). Our assumption is that the element is considered visible (i.e. Capybara::Selenium::ChromeNode#visible?
returns true
for such elements) but the Selenium driver wants to actually click the center of the element which is outside of the viewport.
We don't know who exactly i...
For my computer science bachelor's thesis I programmed and evaluated a CLI Test Case Prioritization (TCP) tool for makandra. It has been written as a Ruby Gem and was tested and evaluated against one Ruby on Rails project. This card will summarize and present the research results, the evaluation and the programmed CLI tool.
The code has been published for educational purposes on GitHub. The german bachelor's thesis has also been included for download at the end.
...
When you minify ("compress", "optimize") your JavaScript for production, the names of your functions and variables will be renamed for brevity. This process is often called mangling.
E.g. if this is your source code:
function function1() {
function2()
}
After mangling it would look like this:
function a() {
b()
}
Minfiers never mangle properties by default, as this can be an unsafe transformation. This leads to larger file sizes if...
If you want to collapse/expand elements with dynamic content (and thus unknown height), you can not transition between height: 0
and height: auto
.
In the past, you might have resorted to bulky JavaScript solutions or CSS hacks like transitioning between max-height: 0
and max-height: 9999px
. All of them were awkward and/or have several edge cases.
With modern CSS, there is actually a way to do it properly:
Just use a display: grid
container which transitions its grid row height betwe...
Note: You won't need this for single lines of text. In this case it is better to just use the text-overflow
property: Use CSS "text-overflow" to truncate long texts
You can use -webkit-line-clamp
in your CSS/SASS to natively render an ellipsis (...
) after a specific amount of lines for a multi-line text in your HTML.
Earlier, it was necessary to implement JavaScript solutions like Superclamp.js to enable this because the browser support has been rather limited...
Suppose you want to implement a publish/subscribe pattern in your Frontend application to react to data changes and events. First, you might be looking for an event emitter library.
Today I learned that vanilla JavaScript comes with a native event emitter, which I've been indirectly using forever. There's no need for extra code!
const emitter = new EventTarget()
emitter.addEventListener('YOLO', () => {
console.log('YOLO');
})
// invoke attached event listeners
emitter.dispatchEvent(new Event('YOLO'));
Using querySelector
or querySelectorAll
in JavaScript, you can easily find descendants of a node that match a given selector.
But what if you want to find only children (i.e. direct descendants) of an element?
Easy: use :scope
. It references the element on which DOM API methods are being called:
element.querySelectorAll(':scope > .your-selector')
Consider this HTML
<body>
<div id="container1">
<div id="container1a">foo</div>
<div id="container1b">bar</div>
<div id="container1c">baz</...
TL;DR Still has caveats.
Code splitting is a feature of JavaScript bundlers that can keep huge libraries out of the main bundle.
Like Webpack esbuild lets you use the await import()
function to load code on demand:
// application.js
const { fun } = await import('library.js')
fun()
However, esbuild's code splitting is disabled by default. The code above would simply [inline](https://en.wiki...
As we are slowly switching from Cucumber scenarios to RSpec feature specs, you might be tempted to write assertions like this one:
feature 'authorization for cards management' do
let(:guest_user) { create(:user, :guest) }
scenario "rejects guest users from adding new cards", js: true do
sign_in guest_user
expect { visit new_cards_path }.to raise_error(Consul::Powerless)
end
end
While this might work under certain circumstances¹, there is a good chance you'll see two exceptions when running this single spec:
When you allow file uploads in your app, a user might upload content that hurts other users.
Our primary concern here is users uploading .html
or .svg
files that can run JavaScript and possibly hijack another user's session.
A secondary concern is that malicious users can upload executables (like an .exe
or .scr
file) and use your server to distribute it. However, modern operating systems usually warn before executing files that were downloaded from t...