Blog
Mert Özen's blog posts on software development, backend, frontend, and DevOps.
CDK Drag and Drop: cdkDrag, cdkDropList, Sortable Lists and Moving Items Between Lists
In CDK Drag and Drop, cdkDropList and cdkDrag handle the dragging and you change the array: apply moveItemInArray and transferArrayItem to a copy, set it on the signal and track rows by identity. The CDK offers no keyboard sorting; we add button alternatives to a reading list and an institutional shipment plan in Bookstore, and measure focus lost on a moved row, touch behavior with a handle and touch-action, and the re-render cost at 500 rows.
Accessibility Test Automation: a11y Checks in CI with axe-core, Lighthouse, Playwright and ESLint, and the Limits of Automation
You protect accessibility in CI not with one tool but with layers: angular-eslint, axe in component tests, page and state scans in a real browser, Lighthouse as a regression alarm, and the manual testing that is still needed. In Bookstore we find a real violation that only appears in one state, set up a GitHub Actions gate that baselines existing debt and fails the build on new violations, and produce a Level A report for the Ministry's checklist.
Accessible Components in Angular: Angular Aria, CDK a11y, Material and Not Writing Your Own Combobox
For complex widgets like a combobox or tabs, the order is: native element, then Angular Material, then headless Angular Aria (stable since 22.0.0), and CDK primitives last. We add search suggestions and book tabs to Bookstore with Angular Aria, measure the three decisions and the hidden-panel CSS the library leaves to us, and show that Signal Forms does not write aria-invalid before wiring up the error connection.
Testing with Screen Readers: Core NVDA, VoiceOver and TalkBack Commands, Reading the Accessibility Tree
Screen reader users usually move through a page by lists of headings, landmarks and links, so testing starts with knowing browse mode versus focus mode and writing down the expected speech from the tree. We cover core NVDA, VoiceOver and TalkBack commands, the WebAIM 2026 survey, building element lists from Chromium's tree, adding a search landmark and book headings to Bookstore, and generating a test script for a manual session.
Dynamic Content and Screen Reader Announcements: Live Regions, ariaNotify(), Form Errors, Toasts and Loading States
Messages that do not move focus (result counts, "added to cart", error counts) reach a screen reader through a live region or ariaNotify(), and a live region must be in the DOM before the change. In Bookstore we measure the role="status" inside @if trap, announce the result count with aria-busy, use ariaNotify() with a CDK LiveAnnouncer fallback, move focus to an error summary and the order confirmation, and look at toasts in terms of 2.2.1 and 4.1.3.
Using WAI-ARIA Correctly: Roles, States, Properties, Accessible Names and "No ARIA Is Better than Bad ARIA"
ARIA changes an element's name, role and state in the accessibility tree but adds no behavior; if a native element exists, it comes first. We measure accessible name sources from Chromium, give same-named buttons context that respects 2.5.3, apply aria-hidden, aria-expanded, aria-current, aria-invalid and aria-describedby in Bookstore, and catch a CSS bug that made the state and the screen disagree.
Keyboard Navigation and Focus Management: Tab Order, :focus-visible, Skip Links, Focus Traps, inert and Roving Tabindex
For keyboard users focus must always be visible, move in a sensible order and be placed somewhere on purpose when the focused element disappears. We use Bookstore with the keyboard only and measure: the base href trap of skip links in an SPA, a sticky header hiding focus and scroll-padding, the native dialog's focus trap and focus after a deleted row, roving tabindex with native radios, and focus and page titles on route changes with the Angular router.
Reading WCAG 2.2 as a Developer: the Most Commonly Failed Criteria and a Bookstore Audit
Lighthouse's accessibility score of 100 only says the automatically measurable part is clean; problems such as non-text contrast, autocomplete, placeholders counted as labels and focus management are only found by a manual audit. The post covers the most common failures from WebAIM Million 2026, the twelve problems found in a Bookstore that scores 100, the first fixes, measuring WCAG 2.2's new criteria and a draft accessibility statement page.
What Is Accessibility and Why Is It Mandatory? WCAG 2.2, POUR, A/AA/AAA and Obligations in Türkiye and the EU
Accessibility means a product can be used by everyone, including people with disabilities, and today it is a legal obligation through Circular 2025/10 in Türkiye and the European Accessibility Act in the EU; in practice both point to WCAG 2.2 AA. The post explains WCAG's structure of POUR, guidelines, success criteria and levels, what changed in 2.2 and what the Circular and the EAA mean for developers; we set up the series' Bookstore lab and run the first axe scan.
Form Design: Label Placement, Error Messages, Inline Validation and Splitting Long Forms
A good form asks for few fields, keeps the label visible above the field, shows no error before the user has finished typing, and on an error says what happened and how to fix it and moves focus to a summary. We cut Bookstore's delivery form from 16 fields to 6 and from 150 characters to type to 54, measure and fix floating labels, asterisks, per-keystroke validation, "Invalid" messages and blocked paste, and apply WCAG 2.2's Redundant Entry and Accessible Authentication criteria.
Color and Contrast: Building a Palette, Semantic Colors, OKLCH and WCAG Contrast Ratios
An interface palette is made of a brand colour, a neutral scale and semantic colours; with OKLCH and the same lightness steps, the same-numbered shade of every colour gives almost the same contrast against white. In Bookstore's catalogue we measure WCAG 2.2 ratios with our own script and axe-core, fix 8 failing texts and a stock status shown by colour alone, re-tune dark mode instead of inverting it, and explain where APCA stands today.