Training Example: Alpine.js – Review the Data, Give Your Score & Compare to the Real AI Evaluation

Industry Context — Common BS Fingerprints in Software, SaaS & Tech Products
Generic Claims: the all-in-one platform, trusted by thousands of companies, increase productivity by X percent, save hours every week…
Red Flags: AI claims without explaining what the AI does, customer logos without case study or testimonial evidence, no live product access or demo, SOC 2 claims without audit period or report availability…
Semantic Drift Patterns: homepage claims AI-powered but product is rules-based, claims enterprise-grade but pricing page shows startup tiers only, homepage shows Fortune 500 logos but case studies are small businesses, claims all-in-one but integration page shows critical missing pieces…
Proof Expectations: live product demo or free trial access, specific feature documentation with screenshots, verified customer logos with published case studies, third-party review scores on G2, Capterra, or TrustRadius…

Alpine.js

(https://alpinejs.dev) 📸 Data Snapshot: May 26, 2026

Analyze the raw signals below. How would a machine score this business’s credibility?

Here are the exact signals captured from up to six pages of the site — the same raw inputs the evaluation engine analyzed. They are grouped by signal type so you can weigh each the way the machine does.

🏗️ Semantic Structure — heading hierarchy & page identity (Info Density · Commodity Fingerprint)
HOMEPAGE Alpine.js (https://alpinejs.dev)
Title

Alpine.js

Meta

A rugged, minimal framework for composing behavior directly in your markup.

H2 Your new, lightweight, JavaScript framework.
H2 Simple.
H2 Lightweight.
H2 Powerful as hell.
NAV_HEADING_REPEATED_BODY Start Here — Alpine.js (https://alpinejs.dev/start-here/)
Title

Start Here — Alpine.js

H1 Start Here
H2 Building a counter
H2 Building a dropdown
H2 Building a search input
H2 Recap
H3 Declaring data
H3 Listening for events
H3 Reacting to changes
H3 Toggling elements
H3 Listening for a click outside
H3 Multi line formatting
H3 Binding to inputs
H3 Computed properties using getters
H3 Looping elements
NAV UI Components — Alpine.js (https://alpinejs.dev/components/)
Title

UI Components — Alpine.js

Meta

Well made, keyboard accessible, UI components written with Alpine.

H1 Alpine UI Components
H2 Well-built, robust, Alpine components for all your needs
H2 Become an Alpine master with our in-depth screencasts
H2 Third-party Integrations
H2 Support this project so that it can keep getting better and better
H2 Lifetime Access
H3 Components
H3 Screencasts
H3 Integrations
H3 Community
H3 Pricing
H4 Get Lifetime Access
📝 The Narrative — clean text per page (Info Density · Semantic Coherence)
HOMEPAGE (https://alpinejs.dev) Alpine.js
[H2] Simple.

[H2] Lightweight.

[H2] Powerful as hell.

Alpine is a rugged, minimal tool for composing behavior directly in your markup.
Think of it like jQuery for the modern web. Plop in a script tag and get going.

Alpine is a collection of 15 attributes, 6 properties, and 2 methods.

There is no better way to get a feel for what Alpine is and what it can do, than by seeing it for yourself:

Show More ↓

x-data
Declare a new Alpine component and its data for a block of HTML

<div x-data="{ open: false }">
...
</div>

x-bind
Dynamically set HTML attributes on an element

<div x-bind:class="! open ? 'hidden' : ''">
...
</div>

x-on
Listen for browser events on an element

<button x-on:click="open = ! open">
Toggle
</button>

x-text
Set the text content of an element

<div>
Copyright ©

<span x-text="new Date().getFullYear()"></span>
</div>

x-html
Set the inner HTML of an element

<div x-html="(await axios.get('/some/html/partial')).data">
...
</div>

x-model
Synchronize a piece of data with an input element

<div x-data="{ search: '' }">
<input type="text" x-model="search">

Searching for: <span x-text="search"></span>
</div>

x-show
Toggle the visibility of an element

<div x-show="open">
...
</div>

x-transition
Transition an element in and out using CSS transitions

<div x-show="open" x-transition>
...
</div>

x-for
Repeat a block of HTML based on a data set

<template x-for="post in posts">
<h2 x-text="post.title"></h2>
</template>

x-if
Conditionally add/remove a block of HTML from the page entirely

<template x-if="open">
<div>...</div>
</template>

x-init
Run code when an element is initialized by Alpine

<div x-init="date = new Date()"></div>

x-effect
Execute a script each time one of its dependencies change

<div x-effect="
2144 chars
SUB-PAGE (https://alpinejs.dev/start-here/) Start Here — Alpine.js
[H1] Start Here
Create a blank HTML file somewhere on your computer with a name like: i-love-alpine.html
Using a text editor, fill the file with these contents:
<html><head> <script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/cdn.min.js"></script></head><body> <h1 x-data="{ message: 'I ❤️ Alpine' }" x-text="message"></h1></body></html>
<html>
<head>
<script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/cdn.min.js"></script>
</head>
<body>
<h1 x-data="{ message: 'I ❤️ Alpine' }" x-text="message"></h1>
</body>
</html>
Open your file in a web browser, if you see I ❤️ Alpine, you're ready to rumble!
Now that you're all set up to play around, let's look at three practical examples as a foundation for teaching you the basics of Alpine. By the end of this exercise, you should be more than equipped to start building stuff on your own. Let's goooooo.
Building a counter
Building a dropdown
Building a search Input
[H2] Building a counter
Let's start with a simple "counter" component to demonstrate the basics of state and event listening in Alpine, two core features.
Insert the following into the <body> tag:
<div x-data="{ count: 0 }"> <button x-on:click="count++">Increment</button>  <span x-text="count"></span></div>
<div x-data="{ count: 0 }">
<button x-on:click="count++">Increment</button>
<span x-text="count"></span>
</div>
Increment

Now, you can see with 3 bits of Alpine sprinkled into this HTML, we've created an interactive "counter" component.
Let's walk through what's happening briefly:
[H3] Declaring data
<div x-data="{ count: 0 }">
<div x-data="{ count: 0 }">
Everything in Alpine starts with an x-data directive. Inside of x-data, in plain JavaScript, you declare an object of data that Alpine will track.
Every property inside this object will be made available to other directives inside this HTML element. In addition, when one of these properties changes, everything that relies on it will change as well.
x-data is required on a parent element for most Alpine directives to work.
→ Read more about x-data
Let's look at x-on and see how it can access and modify the count property from above:
[H3] Listening for events
<button x-on:click="count++">Increment</button>
<button x-on:click="count++">Increment</button>
x-on is a directive you can use to listen for any event on an element. We're listening for a click event in this case, so ours looks like x-on:click.
You can listen for other events as you'd imagine. For example, listening for a mouseenter event would look like this: x-on:mouseenter.
When a click event happens, Alpine will call the associated JavaScript expression, count++ in our case. As you can see, we have direct access to data declared in the x-data expression.
You will often see @ instead of x-on:. This is a shorter, friendlier syntax that many prefer. From now on, this documentation will likely use @ instead of x-on:.
→ Read more about x-on
[H3] Reacting to changes
<span x-text="count"></span>
<span x-text="count"></span>
x-text is an Alpine directive you can use to set the text content of an element to the result of a JavaScript expression.
In this case, we're telling Alpine to always make sure that the contents of this span tag reflect the value of the count property.
In case it's not clear, x-text, like most directives accepts a plain JavaScript expression as an argument. So for example, you could instead set its contents to: x-text="count * 2" and the text content of the span will now always be 2 times the value of count.
→ Read more about x-text
[H2] Building a dropdown
Now that we've seen some basic functionality, let's keep going and look at an important directive in Alpine: x-show, by building a contrived "dropdown" component.
Insert the following code into the <body> tag:
<div x-data="{ open: false }"> <button @click="open = ! open">Toggle</button>  <div x-show="open" @click.outside="open = false">Contents...</div></div>
<div x-data="{ open: false }">
<button @click="open = ! open">Toggle</button>
<div x-show="open" @click.outside="open = false">Contents...</div>
</div>
Toggle
Contents...
If you load this component, you should see that the "Contents..." are hidden by default. You can toggle showing them on the page by clicking the "Toggle" button.
The x-data and x-on directives should be familiar to you from the previous example, so we'll skip those explanations.
[H3] Toggling elements
<div x-show="open" ...>Contents...</div>
<div x-show="open" ...>Contents...</div>
x-show is an extremely powerful directive in Alpine that can be used to show and hide a block of HTML on a page based on the result of a JavaScript expression, in our case: open.
→ Read more about x-show
[H3] Listening for a click outside
<div ... @click.outside="open = false">Contents...</div>
<div ... @click.outside="open = false">Contents...</div>
You'll notice something new in this example: .outside. Many directives in Alpine accept "modifiers" that are chained onto the end of the directive and are separated by periods.
In this case, .outside tells Alpine to instead of listening for a click INSIDE the <div>, to listen for the click only if it happens OUTSIDE the <div>.
This is a convenience helper built into Alpine because this is a common need and implementing it by hand is annoying and complex.
→ Read more about x-on modifiers
[H2] Building a search input
Let's now build a more complex component and introduce a handful of other directives and patterns.
Insert the following code into the <body> tag:
<div x-data="{ search: '',  items: ['foo', 'bar', 'baz'],  get filteredItems() { return this.items.filter( i => i.startsWith(this.search) ) } }"> <input x-model="search" placeholder="Search...">  <ul> <template x-for="item in filteredItems" :key="item"> <li x-text="item"></li> </template> </ul></div>
<div
x-data="{
search: '',
items: ['foo', 'bar', 'baz'],
get filteredItems() {
return this.items.filter(
i => i.startsWith(this.search)
)
}
}"
>
<input x-model="search" placeholder="Search...">
<ul>
<template x-for="item in filteredItems" :key="item">
<li x-text="item"></li>
</template>
</ul>
</div>

By default, all of the "items" (foo, bar, and baz) will be shown on the page, but you can filter them by typing into the text input. As you type, the list of items will change to reflect what you're searching for.
Now there's quite a bit happening here, so let's go through this snippet piece by piece.
[H3] Multi line formatting
The first thing I'd like to point out is that x-data now has a lot more going on in it than before. To make it easier to write and read, we've split it up into multiple lines in our HTML. This is completely optional and we'll talk more in a bit about how to avoid this problem altogether, but for now, we'll keep all of this JavaScript directly in the HTML.
[H3] Binding to inputs
<input x-model="search" placeholder="Search...">
<input x-model="search" placeholder="Search...">
You'll notice a new directive we haven't seen yet: x-model.
x-model is used to "bind" the value of an input element with a data property: "search" from x-data="{ search: '', ... }" in our case.
This means that anytime the value of the input changes, the value of "search" will change to reflect that.
x-model is capable of much more than this simple example.
→ Read more about x-model
[H3] Computed properties using getters
The next bit I'd like to draw your attention to is the items and filteredItems properties from the x-data directive.
{ ... items: ['foo', 'bar', 'baz'],  get filteredItems() { return this.items.filter( i => i.startsWith(this.search) ) }}
{
...
items: ['foo', 'bar', 'baz'],
get filteredItems() {
return this.items.filter(
i => i.startsWith(this.search)
)
}
}
The items property should be self-explanatory. Here we are setting the value of items to a JavaScript array of 3 different items (foo, bar, and baz).
The interesting part of this snippet is the filteredItems property.
Denoted by the get prefix for this property, filteredItems is a "getter" property in this object. This means we can access filteredItems as if it was a normal property in our data object, but when we do, JavaScript will evaluate the provided function under the hood and return the result.
It's completely acceptable to forgo the get and just make this a method that you can call from the template, but some prefer the nicer syntax of the getter.
→ Read more about JavaScript getters
Now let's look inside the filteredItems getter and make sure we understand what's going on there:
return this.items.filter( i => i.startsWith(this.search))
return this.items.filter(
i => i.startsWith(this.search)
)
This is all plain JavaScript. We are first getting the array of items (foo, bar, and baz) and filtering them using the provided callback: i => i.startsWith(this.search).
By passing in this callback to filter, we are telling JavaScript to only return the items that start with the string: this.search, which like we saw with x-model will always reflect the value of the input.
You may notice that up until now, we haven't had to use this. to reference properties. However, because we are working directly inside the x-data object, we must reference any properties using this.[property] instead of simply [property].
Because Alpine is a "reactive" framework. Any time the value of this.search changes, parts of the template that use filteredItems will automatically be updated.
[H3] Looping elements
Now that we understand the data part of our component, let's understand what's happening in the template that allows us to loop through filteredItems on the page.
<ul> <template x-for="item in filteredItems"> <li x-text="item"></li> </template></ul>
<ul>
<template x-for="item in filteredItems">
<li x-text="item"></li>
</template>
</ul>
The first thing to notice here is the x-for directive. x-for expressions take the following form: [item] in [items] where [items] is any array of data, and [item] is the name of the variable that will be assigned to an iteration inside the loop.
Also notice that x-for is declared on a <template> element and not directly on the <li>. This is a requirement of using x-for. It allows Alpine to leverage the existing behavior of <template> tags in the browser to its advantage.
Now any element inside the <template> tag will be repeated for every item inside filteredItems and all expressions evaluated inside the loop will have direct access to the iteration variable (item in this case).
→ Read more about x-for
[H2] Recap
If you've made it this far, you've been exposed to the following directives in Alpine:
x-data
x-on
x-text
x-show
x-model
x-for
That's a great start, however, there are many more directives to sink your teeth into. The best way to absorb Alpine is to read through this documentation. No need to comb over every word, but if you at least glance through every page you will be MUCH more effective when using Alpine.
Happy Coding!

Upgrade From V2 →

Code highlighting provided by Torchlight
11672 chars
SUB-PAGE (https://alpinejs.dev/components/) UI Components — Alpine.js
[H1]
Do amazing things with Alpine.
We've done the hard work and sweated the details, so you can just copy and paste them into your app and spend less time re-inventing the wheel.
Learn more
Get access

[H3]
Components

[H2] Well-built, robust, Alpine components for all your needs

Most websites need UI components like modals, dropdowns, tabs, etc. Building them properly yourself is anything but trivial.
Instead, we've done the hard work and sweated the details, so you can just copy and paste them into your app and spend less time re-inventing the wheel.

Dropdown
Preview

Modal
Preview

Accordion
Preview

Carousel
Preview

Tabs
Preview

Notifications
Preview

Radio Group
Preview

Toggle
Preview

Tooltip
Preview

[H3]
Screencasts
[H2] Become an Alpine master with our in-depth screencasts
Every UI component comes with an in-depth screencast to go along with it. This way, in addition to getting production-ready components, you get training and instruction to build and modify them for yourself.
On top of that, what better way is there to level up your front-end skills by watching the Alpine creator himself tackle real-life problems and guide you every step of the way.

[IMG: Caleb]

[H3]
Integrations
[H2] Third-party Integrations
There's a wealth of third-party tools and libraries available to tackle hard problems like charting, rich-text editing, etc. Unfortunately, getting them all to play nicely with your Alpine app can be challenging. We've done that work for you.
We've built custom code and tutorials for integrating with the most popular open source libraries that will get you up and running with them in no time.

Charts

Chart.js

ApexCharts

Text Editors

Trix

Quill

SimpleMDE

Select Inputs

Select2

Choices.js

Calendars & Datepickers

Flatpickr

Date Range Picker

FullCalendar

Carousels

Glide

Splide

[H3]
Community
[H2] Support this project so that it can keep getting better and better
Open Source code like Alpine is freely available for you to use and profit from however you like. However, building something of value takes time and resources.
By purchasing a product like "Alpine UI Components" you are funding development on Alpine. Making sure it keeps improving, stays bug free, and ultimately has a bright future.

Alpine UI Components are awesome! I love that you can just copy and paste the basic integration of a component, but if you want to go deeper, a professional video tutorial is right there to help you out.

Eric L. Barnes
Creator of Laravel News

[H3]
Pricing
[H2] Lifetime Access
Get access to all Alpine UI Components including future updates and additions for a single low price.

[H4]
Get Lifetime Access
$49

$99

Practical, entertaining, screencasts

9+ Robust UI components

12+ Third-party library integrations

9+ Headless Alpine components

Copy-pastable source code

Access to updates and improvements forever

Get Access

Close dialog
3196 chars
🛡️ Trust Signals — reviews, proof links, trust-theatre flag (Trust & Proof)
11Review mentions (all pages)
0External proof links (all pages)
PageReviewsProof links
/ (home) 0 0
/start-here/ 0 0
/components/ 11 0
🔗 Identity & Technical Layer — schema JSON-LD: identity chains, entity gaps (Identity & Authority)
Homepage — no schema detected (entity gap)
/start-here/ — no schema detected (entity gap)
/components/ — no schema detected (entity gap)

Your Diagnosis

Before revealing the machine’s verdict, predict the BS score for each signal. Higher = more BS (more fluff, less verifiable substance). Drag each slider, then submit to compare your judgment against the engine.

Information Density 0 / 30
Read the Narrative & headings: do hard facts (prices, dates, numbers) outweigh fluff power-words?
Semantic Coherence 0 / 20
Compare the homepage promise against the sub-page reality. Do they hold the same line?
Trust & Proof 0 / 20
Weigh review mentions against actual external proof links. Claims without verification = theatre.
Commodity Fingerprint 0 / 15
Check headings & narrative against the industry clichés in the setup above.
Identity & Authority 0 / 15
Inspect the schema: is there real Organization/Person identity with sameAs links, or gaps?
Your predicted BS score 0 / 100
💡 Stuck? Reveal the heuristic lens — how the deterministic page-auditor reads each signal (no AI, pure pattern rules)

These are the structural rules a local, deterministic auditor applies — the same lens you can use to judge each signal. They describe what to look for, not this company’s result.

Information Density

Classify each sentence as substantive or hollow. Grounding markers — numbers, currencies, dates, technical units, named entities — outweigh marketing adjectives. When fluff sits right next to hard evidence, the fluff is forgiven.

Semantic Alignment

Pull the main entities out of the H1, then check whether they actually recur through the body. A page that announces one thing and then talks about another drifts. Headings with no real sentences underneath read as pseudo-substance.

Trust & Proof

Count trust words (review, testimonial, rating, verified) against real outbound proof links (Google, Trustpilot, Clutch, G2, Yelp). Lots of trust language with zero verification links is trust theatre. Unlinked logo galleries count against it.

Commodity Fingerprint

Look at how much sentence length varies. Natural writing varies its rhythm; templated or mass-produced copy is statistically uniform. Very low variation reads as commodity content — unless unique named entities break the pattern.

Identity & Authority

Inspect the JSON-LD. Is there an Organization or Person schema, and does it carry sameAs links to real external profiles (LinkedIn, socials)? Missing schema or no identity declaration signals an anonymous entity.

Want to apply this lens yourself? The free BS Indicator Chrome extension runs these heuristic checks live on any page. Bear in mind it is a single-page, deterministic tool — it relies only on pattern rules for the page in front of it and does not perform the cross-page semantic correlation this audit uses, so its readout is a starting lens, not the full verdict.

B
BS Level
Software, SaaS & Tech Products
32.8 Avg BS

Based on 1098 businesses audited.

BS Detector

Software, SaaS & Tech Products BS: Alpine.js (alpinejs.dev)

https://alpinejs.dev 📍 Industry: Software, SaaS & Tech Products
12 BS / 100

Alpine.js is a masterclass in Signal-to-Substance ratio, using code as a primary language to eliminate marketing noise. It is one of the rare instances where ‘Powerful as hell’ feels like a technical description rather than a vacuous boast. The BS score is driven only by minor technical omissions in structured data and a few standard industry adjectives.

Info Density Power-words vs. Substance ratio.
2
7% BS
Semantic Coherence Homepage promise vs. Sub-page reality.
0
0% BS
Trust & Proof Verifiable evidence vs. Trust Theatre.
3
15% BS
Commodity Fingerprint Detection of industry clichés/templates.
2
13% BS
Identity & Authority Expert verifiability & Schema depth.
5
33% BS

Implement Organization and Person schema to formally link Caleb Porzio and the brand to verified external profiles. Add a dedicated ‘Changelog’ or ‘Version History’ page to provide temporal proof of active development. Link the ’11 reviews’ on the components page to a third-party platform or a dedicated testimonials page with project links. Avoid the word ‘robust’ in headings and replace it with more specific technical outcomes like ‘WAI-ARIA compliant.’

The website perfectly aligns with the Software and Developer Tools category. Its content is exclusively technical, focusing on JavaScript framework implementation, syntax, and UI component documentation rather than generic business metrics.

“The score of 12 is primarily derived from the lack of structured data (Identity & Authority) and the presence of unlinked reviews (Trust and Proof). The site's core messaging (Information Density and Semantic Coherence) is virtually fluff-free. It successfully avoids the 'Commodity Fingerprint' by using highly specific developer-centric positioning.”

Verified Analysis Date: May 26, 2026 © 1EuroSEO Independent Evaluator — Non-Sponsored Result