Let's break it down, starting with the foundational left-to-right tree, where only a couple dozen lines of CSS can transform this ... into this ...
🧵
Let's break it down, starting with the foundational left-to-right tree, where only a couple dozen lines of CSS can transform this ... into this ...
🧵
Use a ui-* prefix: ui-button, ui-input, ui-badge.
Here's why naming matters more than you think...
Use a ui-* prefix: ui-button, ui-input, ui-badge.
Here's why naming matters more than you think...
We need to be able to compose behaviors and appearance as needed. A <label> might need to look like a button, or <summary>, or <input type=radio>
Visual affordances deserve their own primitive.
We need to be able to compose behaviors and appearance as needed. A <label> might need to look like a button, or <summary>, or <input type=radio>
Visual affordances deserve their own primitive.
I'll give a full behind-the-scenes tour of the project to the first person that comments with the correct essential implementation details driving this "card tabs" component.
I'll give a full behind-the-scenes tour of the project to the first person that comments with the correct essential implementation details driving this "card tabs" component.
Add a <text fill=transparent> node with the corresponding text.
We can have nice things that are usable too!
Add a <text fill=transparent> node with the corresponding text.
We can have nice things that are usable too!
Borrowed the visual design from Campsite, but built with native
Borrowed the visual design from Campsite, but built with native
Add it to an interactive element like a button, link, or input so users can fire its default action via keyboard shortcut, no JS required!
Add it to an interactive element like a button, link, or input so users can fire its default action via keyboard shortcut, no JS required!
Excited seeing it take shape! 👀
Excited seeing it take shape! 👀
nav > ol > li:not(:last-child)::after {
content: " / ";
color: lightgray;
padding: 0 0.5em;
}
The `:not(:last-child)` ensures no trailing separator after the final item.
#StylishHTML
nav > ol > li:not(:last-child)::after {
content: " / ";
color: lightgray;
padding: 0 0.5em;
}
The `:not(:last-child)` ensures no trailing separator after the final item.
#StylishHTML
fractaledmind.com/2025/12/18/...
So I stole their design and rebuilt it with semantic HTML and CSS. 😅
fractaledmind.com/2025/12/18/...
So I stole their design and rebuilt it with semantic HTML and CSS. 😅
fractaledmind.com/2025/12/18/...
Inline SVGs? Bloated DOM.
<img> tags? Can't change colors.
Icon fonts? Blurry at certain sizes, a11y issues.
CSS background-image? Still can't change colors.
But, today there's actually a perfect solution...
Inline SVGs? Bloated DOM.
<img> tags? Can't change colors.
Icon fonts? Blurry at certain sizes, a11y issues.
CSS background-image? Still can't change colors.
But, today there's actually a perfect solution...
Tailwind is utility-FIRST, not utility-ONLY. And @utility and @apply are criminally underused. And here is why this matters...
Tailwind is utility-FIRST, not utility-ONLY. And @utility and @apply are criminally underused. And here is why this matters...
It finds usability issues that happen to block keyboard users first.
Broken focus order, invisible states, unreachable controls—these aren’t “accessibility bugs.” They’re just bugs. Keyboard users hit them before anyone else notices.
It finds usability issues that happen to block keyboard users first.
Broken focus order, invisible states, unreachable controls—these aren’t “accessibility bugs.” They’re just bugs. Keyboard users hit them before anyone else notices.
Focus disappears? Problem.
Can’t reach the nav? Problem.
Trapped in a modal? Problem.
It’s a stress test for your whole UI in one keystroke.
Focus disappears? Problem.
Can’t reach the nav? Problem.
Trapped in a modal? Problem.
It’s a stress test for your whole UI in one keystroke.
Your keyboard users can’t complete your signup flow.
These aren’t contradictory. We’ve just been measuring the wrong thing.
Your keyboard users can’t complete your signup flow.
These aren’t contradictory. We’ve just been measuring the wrong thing.
We’ve been testing the wrong thing.
We’ve been testing the wrong thing.
Can you tell what’s focused? Can you reach the main CTA? Can you get back out of the menu?
That 30-second test tells you more than your lighthouse score ever will.
Can you tell what’s focused? Can you reach the main CTA? Can you get back out of the menu?
That 30-second test tells you more than your lighthouse score ever will.
Where does focus land? Can you see it? Can you reach everything? Can you escape that modal?
Your linter can’t answer these. They’re also the only questions that matter.
Where does focus land? Can you see it? Can you reach everything? Can you escape that modal?
Your linter can’t answer these. They’re also the only questions that matter.
Here are three of my favorite landing pages that use the TUI aesthetic:
* openstatus
* turbopuffer
* planetscale
screenshots attached. I want you to redesign the HTML I've attached to get something that both feels unique and familiar with these.
➡️ gemini.google.com/app/f1ee065a...
Here are three of my favorite landing pages that use the TUI aesthetic:
* openstatus
* turbopuffer
* planetscale
screenshots attached. I want you to redesign the HTML I've attached to get something that both feels unique and familiar with these.
➡️ gemini.google.com/app/f1ee065a...
Connect Bluesky
Enter your Bluesky handle and app password to unlock posting, likes, and your Following feed.
Need an app password? Open Bluesky, go to Settings > App passwords, and create a new one.
Connect with Bluesky
Sign in with your Bluesky account to unlock posting, likes, and your Following feed.