# Bestax-Bulma > A Bulma React component library. LLM-friendly documentation for @allxsmith/bestax-bulma. This file contains all documentation content in a single document following the llmstxt.org standard. ## Quick Start ## Create a Bestax App The fastest way to get started. The scaffolder sets up a Vite + React project with bestax-bulma and CSS pre-configured: ```bash pnpm create bestax@latest my-bestax-app cd my-bestax-app pnpm install pnpm dev ``` :::info CSS is included automatically The scaffolder configures `bestax.css` for you — a single stylesheet that includes both Bulma and all bestax extras. No manual CSS setup needed. ::: That's it! Visit http://localhost:5173 to see your app. Skip ahead to [Next Steps](#next-steps), or keep reading to add bestax to an existing project. --- ## Add to an Existing Project ### Install Dependencies ```bash pnpm add @allxsmith/bestax-bulma ``` ### Add Bestax CSS Import the combined stylesheet in your application entry point (e.g. `main.jsx`, `main.tsx`, `index.js`): ```js ``` This single import includes both Bulma base styles and all bestax extras. :::tip Already using Bulma? If you already import Bulma CSS separately, you can keep that and just add the extras: ```js ``` ::: --- ## Use Your First Component Replace `src/App.jsx` (or add to your existing app): ```jsx title="src/App.jsx" function App() { const [showAlert, setShowAlert] = useState(false); return ( Welcome to bestax-bulma! {showAlert && ( Great! You're ready to build with bestax-bulma. )} ); } export default App; ``` --- ## Run Your App ```bash pnpm dev ``` Visit http://localhost:5173 to see your app running. --- ## Next Steps - [Installation Options](/docs/guides/getting-started/installation) -- Icon libraries, CDN, custom Bulma builds, and more - [Extra Components](/docs/guides/library/components) -- Toast, Dialog, Slider, Switch, and other extras - [Toolchains](/docs/guides/getting-started/react-setups) -- Next.js, TypeScript, and Create React App guides - [Browse Components](/docs/category/elements) -- Full API docs and live examples --- ## Custom Component # Custom Component skill The [`bestax-custom-component`](https://github.com/allxsmith/bestax/blob/main/skills/bestax-custom-component/SKILL.md) skill teaches an agent to build a new custom component the bestax way — starting by **checking whether a matching component already exists**, then the helper hooks and the Bulma v1 SCSS pattern, plus stories, tests, and docs. ## Install ```bash npx skills add https://github.com/allxsmith/bestax --skill bestax-custom-component ``` ## Example An agent was asked to build a `ProfileCard` and followed the skill. ### Prompt ```text Build a ProfileCard component — avatar on top, then name, role, and a short description — following the bestax custom-component skill. ``` :::info What the skill checked first There is no `ProfileCard` in the library — but `Card`, `Image`, `Title`, `SubTitle`, and `Content` already exist. So rather than reinventing them, `ProfileCard` is a new component that **composes** the existing elements and adds only its own layout. (Had the request been a "label" or "badge", the skill would have stopped and pointed at the existing `Tag` / `Tags`.) ::: ### Live result ```tsx live function example() { return ( English mathematician who worked on Charles Babbage's proposed Analytical Engine. She was the first to recognise that the machine had applications beyond pure calculation, and published what is now regarded as the first algorithm intended to be carried out by a machine. British mathematician and logician who formalised the concepts of algorithm and computation with the Turing machine. His wartime codebreaking at Bletchley Park helped shorten the Second World War, and he is widely considered the father of theoretical computer science. ); } ``` ### Generated code ```tsx // Compose the existing elements rather than reinventing them. export interface ProfileCardProps extends Omit, 'title' | 'color'>, BulmaClassesProps { name: string; role?: string; imageSrc: string; imageAlt?: string; } export const ProfileCard = forwardRef( ({ name, role, imageSrc, imageAlt, className, children, ...props }, ref) => { const { bulmaHelperClasses, rest } = useBulmaClasses(props); const cardClass = usePrefixedClassNames('profile-card'); const imageClass = usePrefixedClassNames('profile-card-image'); const bodyClass = usePrefixedClassNames('profile-card-body'); const combined = classNames(cardClass, bulmaHelperClasses, className); return ( {imageAlt {name} {role && ( {role} )} {children && {children}} ); } ); ProfileCard.displayName = 'ProfileCard'; export default ProfileCard; ``` ```scss @use 'bulma/sass/utilities/initial-variables' as iv; @use 'bulma/sass/utilities/css-variables' as cv; $profile-card-width: 20rem !default; $profile-card-min-height: 26rem !default; $profile-card-avatar-size: 9rem !default; $profile-card-background: cv.getVar('scheme-main') !default; $profile-card-border: cv.getVar('border-weak') !default; $profile-card-radius: cv.getVar('radius-large') !default; $profile-card-shadow: 0 0.5em 1em -0.125em hsla(0, 0%, 4%, 0.1) !default; $profile-card-padding: 1.5rem !default; $profile-card-gap: 0.75rem !default; .#{iv.$class-prefix}profile-card { @include cv.register-vars( ( 'profile-card-width': #{$profile-card-width}, 'profile-card-min-height': #{$profile-card-min-height}, 'profile-card-avatar-size': #{$profile-card-avatar-size}, 'profile-card-background': #{$profile-card-background}, 'profile-card-border': #{$profile-card-border}, 'profile-card-radius': #{$profile-card-radius}, 'profile-card-shadow': #{$profile-card-shadow}, 'profile-card-padding': #{$profile-card-padding}, 'profile-card-gap': #{$profile-card-gap}, ) ); } .#{iv.$class-prefix}profile-card { display: flex; flex-direction: column; align-items: center; // horizontal centering of the column text-align: center; width: cv.getVar('profile-card-width'); min-height: cv.getVar('profile-card-min-height'); max-width: 100%; gap: cv.getVar('profile-card-gap'); padding: cv.getVar('profile-card-padding'); background-color: cv.getVar('profile-card-background'); border: 1px solid cv.getVar('profile-card-border'); border-radius: cv.getVar('profile-card-radius'); box-shadow: cv.getVar('profile-card-shadow'); } .#{iv.$class-prefix}profile-card-image { display: flex; justify-content: center; } // Enlarge the composed avatar and crop (not stretch) the portrait to a circle. .#{iv.$class-prefix}profile-card-image .#{iv.$class-prefix}image { width: cv.getVar('profile-card-avatar-size'); height: cv.getVar('profile-card-avatar-size'); } .#{iv.$class-prefix}profile-card-image .#{iv.$class-prefix}image img { width: 100%; height: 100%; object-fit: cover; } .#{iv.$class-prefix}profile-card-body { display: flex; flex-direction: column; gap: 0.25rem; } ``` ```tsx Wrote the first algorithm intended to be carried out by a machine. ; ``` :::note `ProfileCard` is an **example** produced by the skill — it is not part of the published `@allxsmith/bestax-bulma` package. The point is the _pattern_ (check first, compose existing elements, follow the SCSS convention, then **inspect it in a browser** to confirm spacing and alignment). See the full skill on [GitHub](https://github.com/allxsmith/bestax/tree/main/skills/bestax-custom-component). ::: --- ## Form # Form skill The [`bestax-form`](https://github.com/allxsmith/bestax/blob/main/skills/bestax-form/SKILL.md) skill teaches an agent to build forms with the bestax form components. There is **no form library** — state is plain React, and errors surface via `color="danger"` + `message` + `messageColor`. ## Install ```bash npx skills add https://github.com/allxsmith/bestax --skill bestax-form ``` ## Signup & validation ### Prompt ```text Build a signup form (name, email, country) that validates on submit and shows inline errors — no form library — following the bestax form skill. ``` ### Live form Click **Create account** with empty fields to see the validation. ```tsx live function example() { const [name, setName] = useState(''); const [email, setEmail] = useState(''); const [country, setCountry] = useState(''); const [submitted, setSubmitted] = useState(false); const errors = { name: !name.trim() ? 'Name is required.' : undefined, email: !/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(email) ? 'Enter a valid email.' : undefined, country: !country ? 'Pick a country.' : undefined, }; const show = k => (submitted ? errors[k] : undefined); return (
{ e.preventDefault(); setSubmitted(true); }} style={{ maxWidth: '28rem' }} > setName(e.target.value)} color={show('name') ? 'danger' : undefined} message={show('name')} messageColor="danger" iconLeftName="user" /> setEmail(e.target.value)} color={show('email') ? 'danger' : undefined} message={show('email')} messageColor="danger" iconLeftName="envelope" />
); } ``` ### Validation pattern Own the state, compute errors, and reflect them on each field with `color="danger"` (colors the input), `message` (the help text), and `messageColor="danger"` (colors the help text). ## Account settings ### Prompt ```text Build an account settings form with a bio, a timezone select, an email-digest radio group, interest checkboxes, and toggle switches — following the bestax form skill. ``` ### Live form ```tsx live function example() { const [bio, setBio] = useState(''); const [timezone, setTimezone] = useState('utc'); const [digest, setDigest] = useState('weekly'); const [interests, setInterests] = useState(['react']); const [darkMode, setDarkMode] = useState(true); const [twoFactor, setTwoFactor] = useState(false); return (