`:\n\n```tsx live\nfunction example() {\n function MyColumns({ children, ...props }) {\n const { bulmaHelperClasses, rest } = useBulmaClasses(props);\n return (\n
\n {children}\n
\n );\n }\n\n return (\n
\n \n Left \n
\n \n Right \n
\n \n );\n}\n```\n\n#### Card\n\n```tsx live\nfunction example() {\n const props = {};\n\n const textColor = 'white';\n const bgColor = 'primary';\n const hasShadow = true;\n const className = 'custom-card';\n const children =
Making a custom card
;\n const p = '4';\n\n const { bulmaHelperClasses, rest } = useBulmaClasses({\n color: textColor,\n backgroundColor: bgColor,\n p,\n ...props,\n });\n const cardClasses = classNames('card', className, bulmaHelperClasses, {\n 'is-shadowless': !hasShadow,\n });\n return (\n
\n {children}\n
\n );\n}\n```\n\n---\n\n### Colors\n\nUse the `color` prop to apply Bulma color classes. Here, each button demonstrates a different color:\n\n```tsx live\n
\n Primary \n Link \n Info \n Success \n Warning \n Danger \n Black \n White \n \n```\n\n### Background Color\n\nComponents expose this helper as `bgColor` (the hook's own parameter is `backgroundColor`). Pair it with a text color that keeps the label readable on each background:\n\n```tsx live\n
\n \n \n Primary\n \n \n \n \n Link\n \n \n \n \n Info\n \n \n \n \n Success\n \n \n \n \n Warning\n \n \n \n \n Danger\n \n \n \n \n Black\n \n \n \n \n White\n \n \n \n```\n\n### Scheme Backgrounds and `bulmaHelperStyles`\n\nThe hook returns a third member, `bulmaHelperStyles`, alongside `bulmaHelperClasses` and `rest`. It is `undefined` for every input except a scheme `backgroundColor` (`scheme-main`, `scheme-main-bis`, `scheme-main-ter`, `scheme-invert`, `scheme-invert-bis`, `scheme-invert-ter`): Bulma ships no `has-background-scheme-*` classes, so those values emit no class and instead surface here as a dark-mode-safe inline style tracking Bulma's scheme CSS variables.\n\n```tsx live\nfunction example() {\n const { bulmaHelperClasses, bulmaHelperStyles, rest } = useBulmaClasses({\n color: 'primary',\n backgroundColor: 'scheme-main-bis',\n id: 'band1',\n });\n\n return JSON.stringify({ bulmaHelperClasses, bulmaHelperStyles, rest });\n // bulmaHelperClasses: 'has-text-primary'\n // bulmaHelperStyles: { backgroundColor: 'var(--bulma-scheme-main-bis)' }\n // rest: { id: 'band1' }\n}\n```\n\nPut it on your element with `mergeBulmaStyles`, which merges the helper style with a user-supplied `style` prop (the user style wins, and the result is `undefined` when both are absent so the DOM stays untouched):\n\n```tsx live\nfunction example() {\n const { bulmaHelperClasses, bulmaHelperStyles, rest } = useBulmaClasses({\n backgroundColor: 'scheme-main-bis',\n p: '4',\n });\n\n return (\n
\n A dark-mode-safe surface with zero custom CSS\n
\n );\n}\n```\n\nIn a real component, destructure `style` out of your own props and pass it as `mergeBulmaStyles`'s second argument (as `Section` does) — if `style` stays in the object you spread, whichever comes later in JSX silently replaces the other instead of merging.\n\n### Color Shade\n\n`colorShade` refines the **text color** — it pairs with the hook's `color` prop (exposed as `textColor` on components, where `color` is the component's own modifier). Here, each line steps through the primary palette:\n\n```tsx live\n<>\n
\n Primary 10\n \n
\n Primary 30\n \n
\n Primary 60\n \n
\n Primary 90\n \n
\n Primary Invert\n \n>\n```\n\n### Background Color Shade\n\nBackground shades use their own prop: `backgroundColorShade` pairs with `backgroundColor`, independently of `colorShade` (which pairs with the text color). Low shade numbers are dark and high numbers are light, so dark shades get light text and light shades get dark text to keep each label readable:\n\n```tsx live\n
\n \n \n Primary 10\n \n \n \n \n Primary 30\n \n \n \n \n Primary 60\n \n \n \n \n Primary 90\n \n \n \n \n Primary Invert\n \n \n \n```\n\nBecause the two shade props are independent, you can shade the text and the background at the same time — a dark background shade with a light text shade of the same color reads well in both themes:\n\n```tsx live\n
\n Primary text shade 85 on a primary background shade 15\n \n```\n\n### Margin\n\nUse margin props to add spacing. Here, margin is applied to buttons, and to a row of buttons using the `Buttons` component:\n\n```tsx live\n<>\n
\n Left \n Margin 4 \n Right \n \n
\n Top/Bottom Margin \n Row 2 \n \n>\n```\n\n### Gap\n\n`gap` puts space between the children of a flex or grid container, and `columnGap` and `rowGap` set one axis. Each whole step is 0.5rem, so `gap=\"2\"` is 1rem and `gap=\"8\"` is 4rem, with half steps such as `\"1.5\"` between them. That is not the margin scale, where `m=\"2\"` is 0.5rem. A step can also be written as a number (`gap={2}`).\n\nThe helpers set the CSS `gap`, which does nothing unless the element lays its children out as flex or grid. Pair them with `display=\"flex\"` or `display=\"grid\"`, or use them on a component that already is one, such as `Buttons` or `Tags`, where they replace the spacing Bulma gives it:\n\n```tsx live\n<>\n
\n One \n Two \n Three \n \n
\n A column \n with a half step \n \n
\n Tighter \n than Bulma's \n default \n \n>\n```\n\n`gapless` removes the gap, the shortcut for `gap=\"0\"`; when both are set, `gap` wins. `columnGap` and `rowGap` win on their own axis over `gap` and `gapless`, so `gap=\"4\" rowGap=\"1\"` spaces the columns 2rem apart and the rows 0.5rem.\n\n`Grid` takes `gap`, `columnGap` and `rowGap` as its own props and renders the same classes. `Columns` keeps its own `gap`, the columns gutter, which takes whole steps; see [Columns](../columns/columns.md).\n\n### Text Size\n\nApply `textSize` to Notifications to illustrate different sizes:\n\n```tsx live\n<>\n
Size 1 \n
Size 3 \n
Size 5 \n
Size 7 \n>\n```\n\n### Text Align\n\nApply `textAlign` to a Box to illustrate text alignment:\n\n```tsx live\n<>\n
Centered text \n
Right aligned text \n
Left aligned text \n>\n```\n\n### Text Transform\n\nApply `textTransform` to a Content tag with a paragraph of the Declaration of Independence:\n\n```tsx live\n<>\n
\n \n \n We hold these truths to be self-evident, that all men are created\n equal...\n
\n \n \n
\n \n \n We hold these truths to be self-evident, that all men are created\n equal...\n
\n \n \n
\n \n \n We hold these truths to be self-evident, that all men are created\n equal...\n
\n \n \n
\n \n \n We hold these truths to be self-evident, that all men are created\n equal...\n
\n \n \n>\n```\n\n### Text Weight\n\nApply `textWeight` to Content tags to illustrate different font weights:\n\n```tsx live\n<>\n
\n \n \n We hold these truths to be self-evident, that all men are created\n equal...\n
\n \n \n
\n \n \n We hold these truths to be self-evident, that all men are created\n equal...\n
\n \n \n
\n \n \n We hold these truths to be self-evident, that all men are created\n equal...\n
\n \n \n
\n \n \n We hold these truths to be self-evident, that all men are created\n equal...\n
\n \n \n>\n```\n\n### Font Family\n\nUse Content blocks with different font families:\n\n```tsx live\n<>\n
\n \n \n We hold these truths to be self-evident, that all men are created\n equal...\n
\n \n \n
\n \n \n We hold these truths to be self-evident, that all men are created\n equal...\n
\n \n \n
\n \n \n We hold these truths to be self-evident, that all men are created\n equal...\n
\n \n \n
\n \n \n We hold these truths to be self-evident, that all men are created\n equal...\n
\n \n \n
\n \n \n We hold these truths to be self-evident, that all men are created\n equal...\n
\n \n \n>\n```\n\n### Visibility\n\nShow three buttons, one hidden, one screen-reader only:\n\n```tsx live\n
\n Hidden \n Screen Reader Only \n Visible \n \n```\n\n### Overflow\n\nShow a Box with clipped overflow:\n\n```tsx live\n
\n This is a very long line of text that will be clipped and not overflow the\n box.\n \n```\n\n`overflow` also takes the CSS keywords Bulma has helpers for (`auto`, `clip`, `hidden`, `scroll`, `visible`), and `overflowX` and `overflowY` set one axis. Beside `overflow`, an axis prop wins on its own axis and `overflow` sets the other, with `clipped` counting as `hidden`, so `overflow=\"hidden\" overflowY=\"auto\"` clips sideways and scrolls down.\n\nHere an aspect ratio fixes the height and the list scrolls inside it. A region that scrolls needs to be reachable from the keyboard, so the example gives it `tabIndex={0}`, a `region` role and a name.\n\n```tsx live\n
\n {Array.from({ length: 20 }, (_, i) => (\n Line {i + 1} of a list longer than the box.
\n ))}\n \n```\n\nWithout `overflowY` the box would grow to fit the list, because an aspect ratio gives way to content that does not fit.\n\n### Overlay\n\n`overlay` is `position: absolute` with `top`, `right`, `bottom` and `left` at 0, so it covers the nearest positioned ancestor. The [position](#position) helpers set `position` with `!important`, so a `pos` or `relative` beside `overlay` replaces the `absolute` and keeps the zero offsets. `overlay pos=\"fixed\"` covers the viewport instead. `sticky`, `relative` and `static` put the element back in the normal flow, where it covers nothing, and a sticky one sticks at every edge of its scroll container.\n\nShow an overlay (toggle with button click):\n\n```tsx\nfunction OverlayExample() {\n const [show, setShow] = useState(false);\n return (\n
\n setShow(s => !s)}>\n {show ? 'Hide Overlay' : 'Show Overlay'}\n \n \n );\n}\n```\n\n### Interaction\n\nShow text in a Box with `unselectable`, and another Box with `clickable`:\n\n```tsx live\n<>\n
This text cannot be selected. \n
This box is clickable. \n>\n```\n\n### Cursor\n\nUse the `cursor` prop to set the cursor style. `'pointer'` reuses Bulma's `is-clickable` class, while `'help'` uses the project-level `is-cursor-help` class:\n\n```tsx live\n<>\n
Cursor: pointer (uses is-clickable) \n
Cursor: help \n>\n```\n\n### Radius\n\n`radiusless` removes the radius; `small`, `normal`, `large` and `rounded` set one from Bulma's radius scale:\n\n```tsx live\n
\n Radiusless \n Small \n Normal \n Large \n Rounded \n \n```\n\nThe class goes on the component's root element, so where an inner element draws the radius, such as the `
` inside `Image`, that element keeps its own. The sizes are not `!important`, unlike `radiusless`, so a component rule more specific than one class still wins: an `isRounded` control stays a pill, and a joined addon keeps its square inner corners.\n\n### Shadowless\n\nShow a Box with `shadowless`:\n\n```tsx live\n
This box has no shadow. \n```\n\n### ClassName\n\nShow a Message with a custom className:\n\n```tsx live\n
\n This message uses a custom className.\n \n```\n\n### Clearfix\n\nShow containers with and without clearfix to demonstrate the importance of clearing floated elements:\n\n```tsx live\n<>\n
\n Without clearfix (container collapses) \n \n \n Left\n \n \n Right\n \n \n \n\n
\n With clearfix (container wraps its floats) \n \n \n Left\n \n \n Right\n \n \n \n>\n```\n\n### Position\n\n`pos` sets CSS `position`: `absolute`, `fixed`, `relative`, `static` or `sticky`. It is named `pos` because several components already have a `position` prop of their own, for where they place a popup or a toast. `relative` is the older shortcut for `pos=\"relative\"` and still works; when both are set, `pos` wins. Beside `overlay`, a `pos` or `relative` replaces the overlay's `absolute` and keeps its zero offsets; see [Overlay](#overlay).\n\nShow a container with relative positioning that provides context for an absolutely positioned child. The helpers set `position` and nothing else, so the child keeps its `top` and `right` offsets inline:\n\n```tsx live\n
\n This container has position: relative \n \n Absolutely positioned child\n \n \n```\n\n`pos=\"sticky\"` needs an offset in the same way, and does nothing until it has one.\n\n### Aspect Ratio\n\n`aspectRatio` fixes an element's width-to-height ratio to one of Bulma's ratios, such as `1by1`, `4by3` or `16by9`, or a portrait one such as `9by16`. The full set is in [Supported Props](#supported-props). The height follows the width:\n\n```tsx live\n
\n \n \n 1by1\n \n \n \n \n 4by3\n \n \n \n \n 16by9\n \n \n \n```\n\nOn `Image`, use its own `size` ratios instead, which also fit the picture to the box.\n\n---\n\n### Skeleton Examples\n\nThe `skeleton` prop applies Bulma's skeleton loading effect. [Skeleton's accessibility notes](../elements/skeleton.md#accessibility) cover it too, reduced motion included. Here are examples for each component:\n\n#### Skeleton Button\n\n```tsx live\n
Skeleton Button \n```\n\n#### Skeleton Buttons Group\n\n```tsx live\n
\n Skeleton \n Skeleton \n Skeleton \n \n```\n\n#### Skeleton Icon\n\n```tsx live\n
\n```\n\n#### Skeleton Image\n\n```tsx live\n
\n```\n\n#### Skeleton Notification\n\n```tsx live\n
Skeleton notification message. \n```\n\n#### Skeleton Tag\n\n```tsx live\n
Skeleton Tag \n```\n\n#### Skeleton Title\n\n```tsx live\n
\n Skeleton Title\n \n```\n\n#### Skeleton SubTitle\n\n```tsx live\n
\n Skeleton SubTitle\n \n```\n\n#### Skeleton Input\n\n```tsx live\n
\n```\n\n#### Skeleton TextArea\n\n```tsx live\n
\n```\n\n---\n\n## API\n\n```tsx\nconst { bulmaHelperClasses, bulmaHelperStyles, rest } = useBulmaClasses(props);\n```\n\n- **props**: An object supporting all Bulma helper class props (see table below), plus any additional props. `backgroundColor` additionally accepts the six [`validSchemeColors`](./valid-values.md) values.\n- **bulmaHelperClasses**: A string of Bulma utility classes to be applied to your element.\n- **bulmaHelperStyles**: `React.CSSProperties | undefined` — an inline style for a scheme `backgroundColor` (see [Scheme Backgrounds](#scheme-backgrounds-and-bulmahelperstyles)); `undefined` for every other input. Apply it with [`mergeBulmaStyles`](#scheme-backgrounds-and-bulmahelperstyles) so a user `style` prop wins.\n- **rest**: An object of all remaining props (with helper props stripped out), suitable for spreading onto your component.\n\n---\n\n## Composable Mini-Hooks\n\n`useBulmaClasses` remains the everything-hook — it is what every bestax-bulma component uses internally, and it covers the full helper prop surface with zero behavior change. If you are building a custom component that only needs a slice of that surface, you can reach for one of seven composable mini hooks instead. Each mini hook accepts just its own group of props and returns a plain class string (except `useColorStyles`, which returns an inline style object or `undefined`), which you can combine with the [`classNames`](./classnames.md) utility.\n\n| Hook | Props Covered | Returns |\n| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `useColorClasses` | `color`, `colorShade`, `backgroundColor`, `backgroundColorShade` | Text and background color classes, including palette shades |\n| `useColorStyles` | `backgroundColor` (scheme values) | `{ backgroundColor: 'var(--bulma-scheme-*)' }` for a scheme background, `undefined` otherwise — the source of `bulmaHelperStyles` |\n| `useSpacingClasses` | `m`, `mt`, `mr`, `mb`, `ml`, `mx`, `my`, `p`, `pt`, `pr`, `pb`, `pl`, `px`, `py`, `gap`, `columnGap`, `rowGap`, `gapless` | Margin, padding and gap classes |\n| `useTypographyClasses` | `textSize`, `textAlign`, `textTransform`, `textWeight`, `fontFamily`, `viewport`, plus `textSize{Mobile..Fullhd}`, `textAlign{Mobile..Fullhd}` | Typography classes, including responsive size/alignment variants |\n| `useVisibilityClasses` | `display`, `visibility`, `viewport`, plus `display{Mobile,Tablet,TabletOnly,Touch,Desktop,DesktopOnly,Widescreen,WidescreenOnly,Fullhd}`, `visibility{Mobile,Tablet,TabletOnly,Touch,Desktop,DesktopOnly,Widescreen,WidescreenOnly,Fullhd}` | Display and visibility classes (this hook owns all display emission) |\n| `useFlexboxClasses` | `flexDirection`, `flexWrap`, `justifyContent`, `alignContent`, `alignItems`, `alignSelf`, `flexGrow`, `flexShrink` | Flexbox classes; container classes are only emitted when a `display`/`display{Viewport}` prop is `flex`/`inline-flex`, item classes (`alignSelf`, `flexGrow`, `flexShrink`) always emit |\n| `useOtherClasses` | `float`, `overflow`, `overflowX`, `overflowY`, `overlay`, `interaction`, `cursor`, `radius`, `shadow`, `responsive`, `skeleton`, `clearfix`, `pos`, `relative`, `fullHeight`, `aspectRatio` | Miscellaneous utility classes |\n\nAll seven hooks (plus `classNames` and `mergeBulmaStyles`) are exported from the package root:\n\n```tsx\nimport {\n useColorClasses,\n useColorStyles,\n useSpacingClasses,\n classNames,\n mergeBulmaStyles,\n} from '@allxsmith/bestax-bulma';\n```\n\nHere is a small custom component that only needs color and spacing helpers:\n\n```tsx live\nfunction example() {\n function PriceTag({\n color,\n backgroundColor,\n backgroundColorShade,\n m,\n children,\n }) {\n const colorClasses = useColorClasses({\n color,\n backgroundColor,\n backgroundColorShade,\n });\n const spacingClasses = useSpacingClasses({ m });\n return (\n
\n {children}\n \n );\n }\n\n return (\n
\n
\n $19.99\n \n
\n $49.99\n \n
\n );\n}\n```\n\n:::note useFlexboxClasses and display\n\n`useFlexboxClasses` only emits container classes (`flexDirection`, `flexWrap`, `justifyContent`, `alignContent`, `alignItems`) when a `display` or `display{Viewport}` prop is `flex` or `inline-flex` — it reads those display props for gating but never emits the display class itself. Pair it with `useVisibilityClasses` (which owns display emission), or just use `useBulmaClasses`.\n\n:::\n\n---\n\n## Supported Props\n\nBelow is the full list of supported props, derived from the `BulmaClassesProps` TypeScript definition:\n\n| Prop | Type / Example Value | Effect / Example Class |\n| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |\n| `color` | `'primary'`, `'link'`, `'info'`, `'success'`, `'warning'`, `'danger'`, `'black'`, `'black-bis'`, `'black-ter'`, `'grey-darker'`, `'grey-dark'`, `'grey'`, `'grey-light'`, `'grey-lighter'`, `'white'`, `'white-bis'`, `'white-ter'`, `'light'`, `'dark'`, `'inherit'`, `'current'` | `has-text-primary`, `has-text-grey-dark`, `has-text-inherit` |\n| `backgroundColor` | Same as `color`, plus the scheme values `'scheme-main'`, `'scheme-main-bis'`, `'scheme-main-ter'`, `'scheme-invert'`, `'scheme-invert-bis'`, `'scheme-invert-ter'` | `has-background-warning`; scheme values emit no class — they return as the `bulmaHelperStyles` inline style |\n| `colorShade` | `'00'`, `'05'`, `'10'`, `'15'`, `'20'`, `'25'`, `'30'`, `'35'`, `'40'`, `'45'`, `'50'`, `'55'`, `'60'`, `'65'`, `'70'`, `'75'`, `'80'`, `'85'`, `'90'`, `'95'`, `'invert'`, `'light'`, `'dark'`, `'soft'`, `'bold'`, `'on-scheme'` | `has-text-primary-25` |\n| `backgroundColorShade` | `'00'`, `'05'`, `'10'`, `'15'`, `'20'`, `'25'`, `'30'`, `'35'`, `'40'`, `'45'`, `'50'`, `'55'`, `'60'`, `'65'`, `'70'`, `'75'`, `'80'`, `'85'`, `'90'`, `'95'`, `'invert'`, `'light'`, `'dark'`, `'soft'`, `'bold'`, `'on-scheme'` | `has-background-info-dark` |\n| `m` | `'0'..'6'`, `'auto'` | `m-4`, `m-auto` |\n| `mt` | `'0'..'6'`, `'auto'` | `mt-2` |\n| `mr` | `'0'..'6'`, `'auto'` | `mr-6` |\n| `mb` | `'0'..'6'`, `'auto'` | `mb-0` |\n| `ml` | `'0'..'6'`, `'auto'` | `ml-auto` |\n| `mx` | `'0'..'6'`, `'auto'` | `mx-2` |\n| `my` | `'0'..'6'`, `'auto'` | `my-5` |\n| `p` | `'0'..'6'`, `'auto'` | `p-3`, `p-auto` |\n| `pt` | `'0'..'6'`, `'auto'` | `pt-1` |\n| `pr` | `'0'..'6'`, `'auto'` | `pr-6` |\n| `pb` | `'0'..'6'`, `'auto'` | `pb-0` |\n| `pl` | `'0'..'6'`, `'auto'` | `pl-4` |\n| `px` | `'0'..'6'`, `'auto'` | `px-1` |\n| `py` | `'0'..'6'`, `'auto'` | `py-6` |\n| `gap` | `'0'..'8'` in half steps, or a number | `is-gap-1.5` |\n| `columnGap` | Same as `gap` | `is-column-gap-4` |\n| `rowGap` | Same as `gap` | `is-row-gap-0.5` |\n| `gapless` | `true` | `is-gapless` |\n| `textSize` | `'1'..'7'` | `is-size-3` |\n| `textAlign` | `'centered'`, `'justified'`, `'left'`, `'right'` | `has-text-centered` |\n| `textTransform` | `'capitalized'`, `'lowercase'`, `'uppercase'`, `'italic'` | `is-uppercase`, `is-italic` |\n| `textWeight` | `'light'`, `'normal'`, `'medium'`, `'semibold'`, `'bold'` | `has-text-weight-bold` |\n| `fontFamily` | `'sans-serif'`, `'monospace'`, `'primary'`, `'secondary'`, `'code'` | `is-family-monospace` |\n| `display` | `'block'`, `'flex'`, `'inline'`, `'inline-block'`, `'inline-flex'`, `'grid'`, `'none'` | `is-flex`, `is-inline-block`, `is-grid`, `is-hidden` |\n| `visibility` | `'hidden'`, `'sr-only'`, `'invisible'` | `is-hidden`, `is-sr-only`, `is-invisible` |\n| `flexDirection` | `'row'`, `'row-reverse'`, `'column'`, `'column-reverse'` | `is-flex-direction-row` |\n| `flexWrap` | `'nowrap'`, `'wrap'`, `'wrap-reverse'` | `is-flex-wrap-nowrap` |\n| `justifyContent` | `'flex-start'`, `'flex-end'`, `'center'`, `'space-between'`, `'space-around'`, `'space-evenly'`, `'start'`, `'end'`, `'left'`, `'right'` | `is-justify-content-center` |\n| `alignContent` | `'flex-start'`, `'flex-end'`, `'center'`, `'space-between'`, `'space-around'`, `'space-evenly'`, `'stretch'` | `is-align-content-stretch` |\n| `alignItems` | `'stretch'`, `'flex-start'`, `'flex-end'`, `'center'`, `'baseline'`, `'start'`, `'end'` | `is-align-items-center` |\n| `alignSelf` | `'auto'`, `'flex-start'`, `'flex-end'`, `'center'`, `'baseline'`, `'stretch'` | `is-align-self-center` |\n| `flexGrow` | `'0'`, `'1'`, `'2'`, `'3'`, `'4'`, `'5'` | `is-flex-grow-1` |\n| `flexShrink` | `'0'`, `'1'`, `'2'`, `'3'`, `'4'`, `'5'` | `is-flex-shrink-0` |\n| `float` | `'left'`, `'right'` | `is-pulled-left`, `is-pulled-right` |\n| `overflow` | `'clipped'`, `'auto'`, `'clip'`, `'hidden'`, `'scroll'`, `'visible'` | `is-clipped`, `is-overflow-auto` |\n| `overflowX` | `'auto'`, `'clip'`, `'hidden'`, `'scroll'`, `'visible'` | `is-overflow-x-auto` |\n| `overflowY` | `'auto'`, `'clip'`, `'hidden'`, `'scroll'`, `'visible'` | `is-overflow-y-scroll` |\n| `overlay` | `true` | `is-overlay` |\n| `interaction` | `'unselectable'`, `'clickable'` | `is-unselectable` |\n| `cursor` | `'pointer'`, `'help'` | `is-clickable`, `is-cursor-help` |\n| `radius` | `'radiusless'`, `'small'`, `'normal'`, `'large'`, `'rounded'` | `is-radiusless`, `has-radius-large` |\n| `shadow` | `'shadowless'` | `is-shadowless` |\n| `responsive` | `'mobile'`, `'narrow'` | `is-mobile`, `is-narrow` |\n| `viewport` | `'mobile'`, `'tablet'`, `'tablet-only'`, `'touch'`, `'desktop'`, `'desktop-only'`, `'widescreen'`, `'widescreen-only'`, `'fullhd'` | Adds viewport suffix to supported properties |\n| `skeleton` | `true` | `is-skeleton` |\n| `clearfix` | `true` | `is-clearfix` |\n| `pos` | `'absolute'`, `'fixed'`, `'relative'`, `'static'`, `'sticky'` | `is-position-sticky` |\n| `relative` | `true` | `is-relative` (ignored when `pos` is set) |\n| `fullHeight` | `true` | `is-full-height` |\n| `aspectRatio` | `'1by1'`, `'5by4'`, `'4by3'`, `'3by2'`, `'5by3'`, `'16by9'`, `'2by1'`, `'3by1'`, `'4by5'`, `'3by4'`, `'2by3'`, `'3by5'`, `'9by16'`, `'1by2'`, `'1by3'` | `is-aspect-ratio-16by9` |\n\n### Viewport-Specific Properties\n\nThe following properties allow you to set different values for each viewport breakpoint:\n\n| Prop | Type / Example Value | Effect / Example Class |\n| -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |\n| `displayMobile` | `'block'`, `'flex'`, `'inline'`, `'grid'`, `'none'`, etc. | `is-block-mobile`, `is-flex-mobile`, `is-hidden-mobile` |\n| `displayTablet` | Same as above | `is-block-tablet`, `is-flex-tablet`, `is-hidden-tablet` |\n| `displayTabletOnly` | Same as above | `is-block-tablet-only`, `is-flex-tablet-only`, `is-hidden-tablet-only` |\n| `displayTouch` | Same as above | `is-block-touch`, `is-flex-touch`, `is-hidden-touch` |\n| `displayDesktop` | Same as above | `is-block-desktop`, `is-flex-desktop`, `is-hidden-desktop` |\n| `displayDesktopOnly` | Same as above | `is-block-desktop-only`, `is-flex-desktop-only`, `is-hidden-desktop-only` |\n| `displayWidescreen` | Same as above | `is-block-widescreen`, `is-flex-widescreen` |\n| `displayWidescreenOnly` | Same as above | `is-block-widescreen-only`, `is-flex-widescreen-only` |\n| `displayFullhd` | Same as above | `is-block-fullhd`, `is-flex-fullhd` |\n| `textSizeMobile` | `'1'..'7'` | `is-size-3-mobile`, `is-size-5-mobile` |\n| `textSizeTablet` | `'1'..'7'` | `is-size-3-tablet`, `is-size-5-tablet` |\n| `textSizeDesktop` | `'1'..'7'` | `is-size-3-desktop`, `is-size-5-desktop` |\n| `textSizeWidescreen` | `'1'..'7'` | `is-size-3-widescreen`, `is-size-5-widescreen` |\n| `textSizeFullhd` | `'1'..'7'` | `is-size-3-fullhd`, `is-size-5-fullhd` |\n| `textAlignMobile` | `'centered'`, `'left'`, `'right'`, `'justified'` | `has-text-centered-mobile`, `has-text-left-mobile` |\n| `textAlignTablet` | Same as above | `has-text-centered-tablet`, `has-text-left-tablet` |\n| `textAlignDesktop` | Same as above | `has-text-centered-desktop`, `has-text-left-desktop` |\n| `textAlignWidescreen` | Same as above | `has-text-centered-widescreen`, `has-text-left-widescreen` |\n| `textAlignFullhd` | Same as above | `has-text-centered-fullhd`, `has-text-left-fullhd` |\n| `visibilityMobile` | `'hidden'`, `'sr-only'`, `'invisible'` | `is-hidden-mobile`, `is-sr-only-mobile`, `is-invisible-mobile` |\n| `visibilityTablet` | Same as above | `is-hidden-tablet`, `is-sr-only-tablet`, `is-invisible-tablet` |\n| `visibilityTabletOnly` | Same as above | `is-hidden-tablet-only`, `is-sr-only-tablet-only`, `is-invisible-tablet-only` |\n| `visibilityTouch` | Same as above | `is-hidden-touch`, `is-sr-only-touch`, `is-invisible-touch` |\n| `visibilityDesktop` | Same as above | `is-hidden-desktop`, `is-sr-only-desktop`, `is-invisible-desktop` |\n| `visibilityDesktopOnly` | Same as above | `is-hidden-desktop-only`, `is-sr-only-desktop-only`, `is-invisible-desktop-only` |\n| `visibilityWidescreen` | Same as above | `is-hidden-widescreen`, `is-sr-only-widescreen`, `is-invisible-widescreen` |\n| `visibilityWidescreenOnly` | Same as above | `is-hidden-widescreen-only`, `is-sr-only-widescreen-only`, `is-invisible-widescreen-only` |\n| `visibilityFullhd` | Same as above | `is-hidden-fullhd`, `is-sr-only-fullhd`, `is-invisible-fullhd` |\n| `responsive` | `'mobile'`, `'narrow'` | `is-mobile`, `is-narrow` |\n| `clearfix` | `true` | `is-clearfix` |\n| `relative` | `true` | `is-relative` |\n| `viewport` | `'mobile'`, `'tablet'`, `'tablet-only'`, `'touch'`, `'desktop'`, `'desktop-only'`, `'widescreen'`, `'widescreen-only'`, `'fullhd'` | Adds suffix, e.g. `-mobile`, `-desktop`, `-touch`, `-tablet-only` |\n\n---\n\n### Full TypeScript Definition\n\n`BulmaClassesProps` is composed from the six group interfaces, each of which is also exported (along with the shared `BulmaViewportProps` and `BulmaDisplayProps` types) and accepted by the corresponding [mini hook](#composable-mini-hooks). The hook's parameter is the widened `BulmaClassesPropsWithScheme` — identical to `BulmaClassesProps` except that `backgroundColor` also accepts the six `validSchemeColors` values (`BulmaColorPropsWithScheme` is the color-group equivalent, accepted by `useColorClasses` and `useColorStyles`):\n\n```ts\nexport interface BulmaClassesProps\n extends\n BulmaColorProps,\n BulmaSpacingProps,\n BulmaTypographyProps,\n BulmaVisibilityProps,\n BulmaFlexboxProps,\n BulmaOtherProps {}\n\nexport type BulmaViewportProps =\n | 'mobile'\n | 'tablet'\n | 'tablet-only'\n | 'touch'\n | 'desktop'\n | 'desktop-only'\n | 'widescreen'\n | 'widescreen-only'\n | 'fullhd';\n\nexport type BulmaDisplayProps =\n | 'block'\n | 'flex'\n | 'inline'\n | 'inline-block'\n | 'inline-flex'\n | 'grid'\n | 'none';\n\nexport interface BulmaColorProps {\n color?:\n | 'primary'\n | 'link'\n | 'info'\n | 'success'\n | 'warning'\n | 'danger'\n | 'black'\n | 'black-bis'\n | 'black-ter'\n | 'grey-darker'\n | 'grey-dark'\n | 'grey'\n | 'grey-light'\n | 'grey-lighter'\n | 'white'\n | 'white-bis'\n | 'white-ter'\n | 'light'\n | 'dark'\n | 'inherit'\n | 'current';\n colorShade?:\n | '00'\n | '05'\n | '10'\n | '15'\n | '20'\n | '25'\n | '30'\n | '35'\n | '40'\n | '45'\n | '50'\n | '55'\n | '60'\n | '65'\n | '70'\n | '75'\n | '80'\n | '85'\n | '90'\n | '95'\n | 'invert'\n | 'light'\n | 'dark'\n | 'soft'\n | 'bold'\n | 'on-scheme';\n backgroundColor?: BulmaColorProps['color'];\n backgroundColorShade?: BulmaColorProps['colorShade'];\n}\n\n// The scheme-aware input accepted by useBulmaClasses, useColorClasses,\n// and useColorStyles ((typeof validSchemeColors)[number] is\n// 'scheme-main' | 'scheme-main-bis' | 'scheme-main-ter'\n// | 'scheme-invert' | 'scheme-invert-bis' | 'scheme-invert-ter'):\nexport type BulmaColorPropsWithScheme = Omit<\n BulmaColorProps,\n 'backgroundColor'\n> & {\n backgroundColor?:\n BulmaColorProps['backgroundColor'] | (typeof validSchemeColors)[number];\n};\n\nexport type BulmaClassesPropsWithScheme = Omit<\n BulmaClassesProps,\n keyof BulmaColorProps\n> &\n BulmaColorPropsWithScheme;\n\nexport interface BulmaSpacingProps {\n m?: '0' | '1' | '2' | '3' | '4' | '5' | '6' | 'auto';\n mt?: '0' | '1' | '2' | '3' | '4' | '5' | '6' | 'auto';\n mr?: '0' | '1' | '2' | '3' | '4' | '5' | '6' | 'auto';\n mb?: '0' | '1' | '2' | '3' | '4' | '5' | '6' | 'auto';\n ml?: '0' | '1' | '2' | '3' | '4' | '5' | '6' | 'auto';\n mx?: '0' | '1' | '2' | '3' | '4' | '5' | '6' | 'auto';\n my?: '0' | '1' | '2' | '3' | '4' | '5' | '6' | 'auto';\n p?: '0' | '1' | '2' | '3' | '4' | '5' | '6' | 'auto';\n pt?: '0' | '1' | '2' | '3' | '4' | '5' | '6' | 'auto';\n pr?: '0' | '1' | '2' | '3' | '4' | '5' | '6' | 'auto';\n pb?: '0' | '1' | '2' | '3' | '4' | '5' | '6' | 'auto';\n pl?: '0' | '1' | '2' | '3' | '4' | '5' | '6' | 'auto';\n px?: '0' | '1' | '2' | '3' | '4' | '5' | '6' | 'auto';\n py?: '0' | '1' | '2' | '3' | '4' | '5' | '6' | 'auto';\n gap?: BulmaGapStep;\n columnGap?: BulmaGapStep;\n rowGap?: BulmaGapStep;\n gapless?: boolean;\n}\n\n// '0' to '8' in half steps ('0', '0.5', '1', … '7.5', '8'), as strings or numbers\nexport type BulmaGapStep =\n | '0'\n | '0.5'\n | '1'\n | '1.5'\n | '2'\n | '2.5'\n | '3'\n | '3.5'\n | '4'\n | '4.5'\n | '5'\n | '5.5'\n | '6'\n | '6.5'\n | '7'\n | '7.5'\n | '8'\n | 0\n | 0.5\n | 1\n | 1.5\n | 2\n | 2.5\n | 3\n | 3.5\n | 4\n | 4.5\n | 5\n | 5.5\n | 6\n | 6.5\n | 7\n | 7.5\n | 8;\n\nexport interface BulmaTypographyProps {\n textSize?: '1' | '2' | '3' | '4' | '5' | '6' | '7';\n textAlign?: 'centered' | 'justified' | 'left' | 'right';\n textTransform?: 'capitalized' | 'lowercase' | 'uppercase' | 'italic';\n textWeight?: 'light' | 'normal' | 'medium' | 'semibold' | 'bold';\n fontFamily?: 'sans-serif' | 'monospace' | 'primary' | 'secondary' | 'code';\n viewport?: BulmaViewportProps;\n textSizeMobile?: '1' | '2' | '3' | '4' | '5' | '6' | '7';\n textSizeTablet?: '1' | '2' | '3' | '4' | '5' | '6' | '7';\n textSizeDesktop?: '1' | '2' | '3' | '4' | '5' | '6' | '7';\n textSizeWidescreen?: '1' | '2' | '3' | '4' | '5' | '6' | '7';\n textSizeFullhd?: '1' | '2' | '3' | '4' | '5' | '6' | '7';\n textAlignMobile?: 'centered' | 'justified' | 'left' | 'right';\n textAlignTablet?: 'centered' | 'justified' | 'left' | 'right';\n textAlignDesktop?: 'centered' | 'justified' | 'left' | 'right';\n textAlignWidescreen?: 'centered' | 'justified' | 'left' | 'right';\n textAlignFullhd?: 'centered' | 'justified' | 'left' | 'right';\n}\n\nexport interface BulmaVisibilityProps {\n display?: BulmaDisplayProps;\n visibility?: 'hidden' | 'sr-only' | 'invisible';\n viewport?: BulmaViewportProps;\n displayMobile?: BulmaDisplayProps;\n displayTablet?: BulmaDisplayProps;\n displayTabletOnly?: BulmaDisplayProps;\n displayTouch?: BulmaDisplayProps;\n displayDesktop?: BulmaDisplayProps;\n displayDesktopOnly?: BulmaDisplayProps;\n displayWidescreen?: BulmaDisplayProps;\n displayWidescreenOnly?: BulmaDisplayProps;\n displayFullhd?: BulmaDisplayProps;\n visibilityMobile?: 'hidden' | 'sr-only' | 'invisible';\n visibilityTablet?: 'hidden' | 'sr-only' | 'invisible';\n visibilityTabletOnly?: 'hidden' | 'sr-only' | 'invisible';\n visibilityTouch?: 'hidden' | 'sr-only' | 'invisible';\n visibilityDesktop?: 'hidden' | 'sr-only' | 'invisible';\n visibilityDesktopOnly?: 'hidden' | 'sr-only' | 'invisible';\n visibilityWidescreen?: 'hidden' | 'sr-only' | 'invisible';\n visibilityWidescreenOnly?: 'hidden' | 'sr-only' | 'invisible';\n visibilityFullhd?: 'hidden' | 'sr-only' | 'invisible';\n}\n\nexport interface BulmaFlexboxProps {\n flexDirection?: 'row' | 'row-reverse' | 'column' | 'column-reverse';\n flexWrap?: 'nowrap' | 'wrap' | 'wrap-reverse';\n justifyContent?:\n | 'flex-start'\n | 'flex-end'\n | 'center'\n | 'space-between'\n | 'space-around'\n | 'space-evenly'\n | 'start'\n | 'end'\n | 'left'\n | 'right';\n alignContent?:\n | 'flex-start'\n | 'flex-end'\n | 'center'\n | 'space-between'\n | 'space-around'\n | 'space-evenly'\n | 'stretch';\n alignItems?:\n | 'stretch'\n | 'flex-start'\n | 'flex-end'\n | 'center'\n | 'baseline'\n | 'start'\n | 'end';\n alignSelf?:\n 'auto' | 'flex-start' | 'flex-end' | 'center' | 'baseline' | 'stretch';\n flexGrow?: '0' | '1' | '2' | '3' | '4' | '5';\n flexShrink?: '0' | '1' | '2' | '3' | '4' | '5';\n}\n\nexport interface BulmaOtherProps {\n float?: 'left' | 'right';\n overflow?: 'clipped' | 'auto' | 'clip' | 'hidden' | 'scroll' | 'visible';\n overflowX?: 'auto' | 'clip' | 'hidden' | 'scroll' | 'visible';\n overflowY?: 'auto' | 'clip' | 'hidden' | 'scroll' | 'visible';\n overlay?: boolean;\n interaction?: 'unselectable' | 'clickable';\n cursor?: 'pointer' | 'help';\n radius?: 'radiusless' | 'small' | 'normal' | 'large' | 'rounded';\n shadow?: 'shadowless';\n responsive?: 'mobile' | 'narrow';\n skeleton?: boolean;\n clearfix?: boolean;\n pos?: 'absolute' | 'fixed' | 'relative' | 'static' | 'sticky';\n relative?: boolean;\n fullHeight?: boolean;\n aspectRatio?:\n | '1by1'\n | '5by4'\n | '4by3'\n | '3by2'\n | '5by3'\n | '16by9'\n | '2by1'\n | '3by1'\n | '4by5'\n | '3by4'\n | '2by3'\n | '3by5'\n | '9by16'\n | '1by2'\n | '1by3';\n}\n```\n\n---\n\n## Responsive Design\n\n### Global Viewport Property (Legacy)\n\nThe `viewport` prop applies a single viewport modifier to ALL properties that support it:\n\n```tsx\nconst { bulmaHelperClasses } = useBulmaClasses({\n color: 'primary',\n textAlign: 'centered',\n textSize: '4',\n viewport: 'mobile', // Applies -mobile to ALL properties\n});\n// Result: has-text-primary-mobile has-text-centered-mobile is-size-4-mobile\n```\n\n### Viewport-Specific Properties (Recommended)\n\nViewport-specific properties allow you to set **different values for each viewport**:\n\n```tsx\nconst { bulmaHelperClasses } = useBulmaClasses({\n // Different text sizes for each viewport\n textSizeMobile: '6', // Small on mobile\n textSizeTablet: '5', // Medium on tablet\n textSizeDesktop: '4', // Large on desktop\n\n // Different text alignment for each viewport\n textAlignMobile: 'centered', // Center on mobile\n textAlignDesktop: 'left', // Left align on desktop\n\n // Different visibility for each viewport\n visibilityMobile: 'hidden', // Hidden on mobile\n visibilityTablet: 'invisible', // Invisible on tablet\n});\n// Result: is-size-6-mobile is-size-5-tablet is-size-4-desktop\n// has-text-centered-mobile has-text-left-desktop is-hidden-mobile is-invisible-tablet\n```\n\n### Breakpoint Reference\n\nBulma's responsive breakpoints:\n\n- **mobile**: up to 768px\n- **tablet**: 769px and above\n- **tablet-only**: 769px - 1023px (excludes desktop and above)\n- **touch**: up to 1023px (mobile + tablet combined — the breakpoint most often used to hide desktop-only chrome)\n- **desktop**: 1024px and above\n- **desktop-only**: 1024px - 1215px (excludes widescreen and above)\n- **widescreen**: 1216px and above\n- **widescreen-only**: 1216px - 1407px (excludes fullhd)\n- **fullhd**: 1408px and above\n\n`display`/`visibility` are the only property families with `*Touch`/`*TabletOnly`/`*DesktopOnly`/`*WidescreenOnly` props; other viewport-aware properties (`textSize*`, `textAlign*`) only go through `mobile`/`tablet`/`desktop`/`widescreen`/`fullhd`, though the generic `viewport` prop itself accepts all nine values for any property that reads it.\n\n### Properties That Support Viewport Modifiers\n\nOnly certain properties support responsive variants:\n\n**✅ Support Viewport Modifiers:**\n\n- Text size (`textSize`, `textSizeMobile`, `textSizeTablet`, etc.)\n- Text alignment (`textAlign`, `textAlignMobile`, `textAlignTablet`, etc.)\n- Display (`display`, `displayMobile`, `displayTablet`, `displayTabletOnly`, `displayTouch`, `displayDesktop`, `displayDesktopOnly`, `displayWidescreen`, `displayWidescreenOnly`, `displayFullhd`)\n- Visibility (`visibility`, `visibilityMobile`, `visibilityTablet`, `visibilityTabletOnly`, `visibilityTouch`, `visibilityDesktop`, `visibilityDesktopOnly`, `visibilityWidescreen`, `visibilityWidescreenOnly`, `visibilityFullhd`)\n\n**❌ Do NOT Support Viewport Modifiers:**\n\n- Spacing (`m`, `mt`, `mr`, `mb`, `ml`, `mx`, `my`, `p`, `pt`, `pr`, `pb`, `pl`, `px`, `py`)\n- Background colors (`backgroundColor`)\n- Flexbox properties (`flexDirection`, `flexWrap`, `justifyContent`, etc.)\n- Other helpers (`float`, `overflow`, `pos`, `radius`, `shadow`, `aspectRatio`, etc.)\n\n---\n\n## Notes\n\n- Any prop not recognized as a Bulma helper prop is passed through in `rest`.\n- Responsive helper props (`viewport`) suffix classes with the breakpoint (e.g., `is-size-3-mobile`).\n- You can use in combination with [`classNames`](./classnames.md) for more advanced use.\n\n---\n\n## See Also\n\n- [classNames helper](./classnames.md)\n- [Bulma Classes Reference](https://bulma.io/documentation/helpers/)\n- [Storybook: useBulmaClasses Demo](https://bestax.io/storybook/?path=/story/helpers-usebulmaclasses--default)",
+ "doc": "# useBulmaClasses\n\n## Overview\n\n`useBulmaClasses` is a custom React hook that generates Bulma helper class strings from a set of props. It makes it easy to apply color, spacing, alignment, typography, flexbox, and other Bulma utility classes to your components in a type-safe, composable way. It also separates out any non-helper props for direct use on elements.\n\n---\n\n## Import\n\n```tsx\nimport { useBulmaClasses } from '@allxsmith/bestax-bulma';\n```\n\n---\n\n## Usage\n\n:::info Container components pad themselves\nContainer components like `Box`, `Notification`, `Message`, and `Card` ship with Bulma's standard, pleasant padding and stack with sensible default spacing. The examples below only add margin or padding props when spacing itself is what's being demonstrated.\n:::\n\n### Basic Example\n\n```tsx live\nfunction example() {\n const { bulmaHelperClasses, rest } = useBulmaClasses({\n color: 'link',\n backgroundColor: 'primary',\n p: '4',\n textAlign: 'centered',\n id: 'card1',\n });\n\n return JSON.stringify({ bulmaHelperClasses, rest });\n // bulmaHelperClasses: 'has-text-link has-background-primary p-4 has-text-centered'\n // rest: { id: 'card1' }\n}\n```\n\nApply to your component:\n\n```tsx live\nfunction example() {\n const { bulmaHelperClasses, rest } = useBulmaClasses({\n color: 'link',\n backgroundColor: 'primary',\n p: '4',\n textAlign: 'centered',\n id: 'card1',\n });\n\n return (\n
\n Card content\n
\n );\n}\n```\n\n---\n\n### Responsive Props\n\n```tsx live\nfunction example() {\n const { bulmaHelperClasses } = useBulmaClasses({\n color: 'link',\n backgroundColor: 'primary',\n m: '2',\n textAlign: 'centered',\n viewport: 'mobile',\n });\n return JSON.stringify({ bulmaHelperClasses });\n // bulmaHelperClasses: 'has-text-link-mobile m-2-mobile has-text-centered-mobile'\n}\n```\n\n---\n\n### Touch and `-only` Viewports\n\nBeyond the five breakpoint props, `display`/`visibility` also take `touch` (mobile + tablet combined — the breakpoint most often used to hide desktop-only chrome) and the `-only` variants (`tablet-only`, `desktop-only`, `widescreen-only`), each isolating a single breakpoint band:\n\n```tsx live\nfunction example() {\n const { bulmaHelperClasses } = useBulmaClasses({\n displayTouch: 'none',\n displayDesktopOnly: 'flex',\n });\n return JSON.stringify({ bulmaHelperClasses });\n // bulmaHelperClasses: 'is-hidden-touch is-flex-desktop-only'\n}\n```\n\n```tsx live\n
\n Hidden on mobile + tablet \n Invisible on desktop only \n Always visible \n \n```\n\nThe legacy `viewport` prop widens to all nine values too, so `useBulmaClasses({ display: 'flex', viewport: 'touch' })` produces `is-flex-touch`. One exception: Bulma ships no `is-size-*` classes for the three `-only` bands, so `textSize` combined with a `tablet-only`/`desktop-only`/`widescreen-only` `viewport` degrades to the base `is-size-N` (rather than emitting a dead `is-size-N-tablet-only`); `touch` and the five breakpoints are unaffected.\n\n---\n\n### Grid Display\n\n`display` also accepts `'grid'`, emitting `is-grid`:\n\n```tsx live\n
\n \n Cell 1\n \n \n Cell 2\n \n \n```\n\n---\n\n### With Flexbox Helpers\n\nFlexbox properties are divided into two categories:\n\n#### Container Properties\n\nThese properties apply to elements with `display: flex` or `display: inline-flex`:\n\n- `flexDirection` - Direction of flex items\n- `flexWrap` - Whether items wrap\n- `justifyContent` - Alignment along main axis\n- `alignContent` - Alignment of wrapped lines\n- `alignItems` - Alignment along cross axis\n\n#### Item Properties\n\nThese properties apply to flex items (children of flex containers) and **do not require** the element itself to have `display: flex`:\n\n- `alignSelf` - Override container's alignItems for this item\n- `flexGrow` - How much the item should grow\n- `flexShrink` - How much the item should shrink\n\n```tsx live\nfunction example() {\n const { bulmaHelperClasses } = useBulmaClasses({\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n gap: '4',\n });\n return JSON.stringify({ bulmaHelperClasses });\n // bulmaHelperClasses: 'is-gap-4 is-flex is-flex-direction-column is-align-items-center is-justify-content-center'\n}\n```\n\nExample with flex items:\n\n```tsx\n// Container with display flex\n
\n {/* Items don't need display flex to use alignSelf, flexGrow, flexShrink */}\n Start \n \n Center & Grow\n \n \n End & No Shrink\n \n \n```\n\n---\n\n### Using with Components\n\n:::note These are illustrations, not replacements\nThe snippets below rebuild simplified components by hand purely to show how `useBulmaClasses` fits inside one. In a real app, use the library's own [Columns / Column](../columns/columns.md) and [Card](../components/card.md) components — they already wire up `useBulmaClasses` (plus prefixes, modifiers, and more) for you.\n:::\n\n#### Columns\n\n`MyColumns` forwards all of its props to `useBulmaClasses` — the `textAlign` and `textTransform` helper props below flow through `props` into the hook (producing `has-text-centered is-uppercase`), while anything the hook doesn't recognize comes back in `rest` and lands on the `
`:\n\n```tsx live\nimport type { BulmaClassesProps } from '@allxsmith/bestax-bulma';\n\nfunction example() {\n function MyColumns({\n children,\n ...props\n }: BulmaClassesProps & React.ComponentPropsWithoutRef<'div'>) {\n const { bulmaHelperClasses, rest } = useBulmaClasses(props);\n return (\n
\n {children}\n
\n );\n }\n\n return (\n
\n \n Left \n
\n \n Right \n
\n \n );\n}\n```\n\n#### Card\n\n```tsx live\nfunction example() {\n const props = {};\n\n const textColor = 'white';\n const bgColor = 'primary';\n const hasShadow = true;\n const className = 'custom-card';\n const children =
Making a custom card
;\n const p = '4';\n\n const { bulmaHelperClasses, rest } = useBulmaClasses({\n color: textColor,\n backgroundColor: bgColor,\n p,\n ...props,\n });\n const cardClasses = classNames('card', className, bulmaHelperClasses, {\n 'is-shadowless': !hasShadow,\n });\n return (\n
\n {children}\n
\n );\n}\n```\n\n---\n\n### Colors\n\nUse the `color` prop to apply Bulma color classes. Here, each button demonstrates a different color:\n\n```tsx live\n
\n Primary \n Link \n Info \n Success \n Warning \n Danger \n Black \n White \n \n```\n\n### Background Color\n\nComponents expose this helper as `bgColor` (the hook's own parameter is `backgroundColor`). Pair it with a text color that keeps the label readable on each background:\n\n```tsx live\n
\n \n \n Primary\n \n \n \n \n Link\n \n \n \n \n Info\n \n \n \n \n Success\n \n \n \n \n Warning\n \n \n \n \n Danger\n \n \n \n \n Black\n \n \n \n \n White\n \n \n \n```\n\n### Scheme Backgrounds and `bulmaHelperStyles`\n\nThe hook returns a third member, `bulmaHelperStyles`, alongside `bulmaHelperClasses` and `rest`. It is `undefined` for every input except a scheme `backgroundColor` (`scheme-main`, `scheme-main-bis`, `scheme-main-ter`, `scheme-invert`, `scheme-invert-bis`, `scheme-invert-ter`): Bulma ships no `has-background-scheme-*` classes, so those values emit no class and instead surface here as a dark-mode-safe inline style tracking Bulma's scheme CSS variables.\n\n```tsx live\nfunction example() {\n const { bulmaHelperClasses, bulmaHelperStyles, rest } = useBulmaClasses({\n color: 'primary',\n backgroundColor: 'scheme-main-bis',\n id: 'band1',\n });\n\n return JSON.stringify({ bulmaHelperClasses, bulmaHelperStyles, rest });\n // bulmaHelperClasses: 'has-text-primary'\n // bulmaHelperStyles: { backgroundColor: 'var(--bulma-scheme-main-bis)' }\n // rest: { id: 'band1' }\n}\n```\n\nPut it on your element with `mergeBulmaStyles`, which merges the helper style with a user-supplied `style` prop (the user style wins, and the result is `undefined` when both are absent so the DOM stays untouched):\n\n```tsx live\nfunction example() {\n const { bulmaHelperClasses, bulmaHelperStyles, rest } = useBulmaClasses({\n backgroundColor: 'scheme-main-bis',\n p: '4',\n });\n\n return (\n
\n A dark-mode-safe surface with zero custom CSS\n
\n );\n}\n```\n\nIn a real component, destructure `style` out of your own props and pass it as `mergeBulmaStyles`'s second argument (as `Section` does) — if `style` stays in the object you spread, whichever comes later in JSX silently replaces the other instead of merging.\n\n### Color Shade\n\n`colorShade` refines the **text color** — it pairs with the hook's `color` prop (exposed as `textColor` on components, where `color` is the component's own modifier). Here, each line steps through the primary palette:\n\n```tsx live\n<>\n
\n Primary 10\n \n
\n Primary 30\n \n
\n Primary 60\n \n
\n Primary 90\n \n
\n Primary Invert\n \n>\n```\n\n### Background Color Shade\n\nBackground shades use their own prop: `backgroundColorShade` pairs with `backgroundColor`, independently of `colorShade` (which pairs with the text color). Low shade numbers are dark and high numbers are light, so dark shades get light text and light shades get dark text to keep each label readable:\n\n```tsx live\n
\n \n \n Primary 10\n \n \n \n \n Primary 30\n \n \n \n \n Primary 60\n \n \n \n \n Primary 90\n \n \n \n \n Primary Invert\n \n \n \n```\n\nBecause the two shade props are independent, you can shade the text and the background at the same time — a dark background shade with a light text shade of the same color reads well in both themes:\n\n```tsx live\n
\n Primary text shade 85 on a primary background shade 15\n \n```\n\n### Margin\n\nUse margin props to add spacing. Here, margin is applied to buttons, and to a row of buttons using the `Buttons` component:\n\n```tsx live\n<>\n
\n Left \n Margin 4 \n Right \n \n
\n Top/Bottom Margin \n Row 2 \n \n>\n```\n\n### Gap\n\n`gap` puts space between the children of a flex or grid container, and `columnGap` and `rowGap` set one axis. Each whole step is 0.5rem, so `gap=\"2\"` is 1rem and `gap=\"8\"` is 4rem, with half steps such as `\"1.5\"` between them. That is not the margin scale, where `m=\"2\"` is 0.5rem. A step can also be written as a number (`gap={2}`).\n\nThe helpers set the CSS `gap`, which does nothing unless the element lays its children out as flex or grid. Pair them with `display=\"flex\"` or `display=\"grid\"`, or use them on a component that already is one, such as `Buttons` or `Tags`, where they replace the spacing Bulma gives it:\n\n```tsx live\n<>\n
\n One \n Two \n Three \n \n
\n A column \n with a half step \n \n
\n Tighter \n than Bulma's \n default \n \n>\n```\n\n`gapless` removes the gap, the shortcut for `gap=\"0\"`; when both are set, `gap` wins. `columnGap` and `rowGap` win on their own axis over `gap` and `gapless`, so `gap=\"4\" rowGap=\"1\"` spaces the columns 2rem apart and the rows 0.5rem.\n\n`Grid` takes `gap`, `columnGap` and `rowGap` as its own props and renders the same classes. `Columns` keeps its own `gap`, the columns gutter, which takes whole steps; see [Columns](../columns/columns.md).\n\n### Text Size\n\nApply `textSize` to Notifications to illustrate different sizes:\n\n```tsx live\n<>\n
Size 1 \n
Size 3 \n
Size 5 \n
Size 7 \n>\n```\n\n### Text Align\n\nApply `textAlign` to a Box to illustrate text alignment:\n\n```tsx live\n<>\n
Centered text \n
Right aligned text \n
Left aligned text \n>\n```\n\n### Text Transform\n\nApply `textTransform` to a Content tag with a paragraph of the Declaration of Independence:\n\n```tsx live\n<>\n
\n \n \n We hold these truths to be self-evident, that all men are created\n equal...\n
\n \n \n
\n \n \n We hold these truths to be self-evident, that all men are created\n equal...\n
\n \n \n
\n \n \n We hold these truths to be self-evident, that all men are created\n equal...\n
\n \n \n
\n \n \n We hold these truths to be self-evident, that all men are created\n equal...\n
\n \n \n>\n```\n\n### Text Weight\n\nApply `textWeight` to Content tags to illustrate different font weights:\n\n```tsx live\n<>\n
\n \n \n We hold these truths to be self-evident, that all men are created\n equal...\n
\n \n \n
\n \n \n We hold these truths to be self-evident, that all men are created\n equal...\n
\n \n \n
\n \n \n We hold these truths to be self-evident, that all men are created\n equal...\n
\n \n \n
\n \n \n We hold these truths to be self-evident, that all men are created\n equal...\n
\n \n \n>\n```\n\n### Font Family\n\nUse Content blocks with different font families:\n\n```tsx live\n<>\n
\n \n \n We hold these truths to be self-evident, that all men are created\n equal...\n
\n \n \n
\n \n \n We hold these truths to be self-evident, that all men are created\n equal...\n
\n \n \n
\n \n \n We hold these truths to be self-evident, that all men are created\n equal...\n
\n \n \n
\n \n \n We hold these truths to be self-evident, that all men are created\n equal...\n
\n \n \n
\n \n \n We hold these truths to be self-evident, that all men are created\n equal...\n
\n \n \n>\n```\n\n### Visibility\n\nShow three buttons, one hidden, one screen-reader only:\n\n```tsx live\n
\n Hidden \n Screen Reader Only \n Visible \n \n```\n\n### Overflow\n\nShow a Box with clipped overflow:\n\n```tsx live\n
\n This is a very long line of text that will be clipped and not overflow the\n box.\n \n```\n\n`overflow` also takes the CSS keywords Bulma has helpers for (`auto`, `clip`, `hidden`, `scroll`, `visible`), and `overflowX` and `overflowY` set one axis. Beside `overflow`, an axis prop wins on its own axis and `overflow` sets the other, with `clipped` counting as `hidden`, so `overflow=\"hidden\" overflowY=\"auto\"` clips sideways and scrolls down.\n\nHere an aspect ratio fixes the height and the list scrolls inside it. A region that scrolls needs to be reachable from the keyboard, so the example gives it `tabIndex={0}`, a `region` role and a name.\n\n```tsx live\n
\n {Array.from({ length: 20 }, (_, i) => (\n Line {i + 1} of a list longer than the box.
\n ))}\n \n```\n\nWithout `overflowY` the box would grow to fit the list, because an aspect ratio gives way to content that does not fit.\n\n### Overlay\n\n`overlay` is `position: absolute` with `top`, `right`, `bottom` and `left` at 0, so it covers the nearest positioned ancestor. The [position](#position) helpers set `position` with `!important`, so a `pos` or `relative` beside `overlay` replaces the `absolute` and keeps the zero offsets. `overlay pos=\"fixed\"` covers the viewport instead. `sticky`, `relative` and `static` put the element back in the normal flow, where it covers nothing, and a sticky one sticks at every edge of its scroll container.\n\nShow an overlay (toggle with button click):\n\n```tsx\nfunction OverlayExample() {\n const [show, setShow] = useState(false);\n return (\n
\n setShow(s => !s)}>\n {show ? 'Hide Overlay' : 'Show Overlay'}\n \n \n );\n}\n```\n\n### Interaction\n\nShow text in a Box with `unselectable`, and another Box with `clickable`:\n\n```tsx live\n<>\n
This text cannot be selected. \n
This box is clickable. \n>\n```\n\n### Cursor\n\nUse the `cursor` prop to set the cursor style. `'pointer'` reuses Bulma's `is-clickable` class, while `'help'` uses the project-level `is-cursor-help` class:\n\n```tsx live\n<>\n
Cursor: pointer (uses is-clickable) \n
Cursor: help \n>\n```\n\n### Radius\n\n`radiusless` removes the radius; `small`, `normal`, `large` and `rounded` set one from Bulma's radius scale:\n\n```tsx live\n
\n Radiusless \n Small \n Normal \n Large \n Rounded \n \n```\n\nThe class goes on the component's root element, so where an inner element draws the radius, such as the `
` inside `Image`, that element keeps its own. The sizes are not `!important`, unlike `radiusless`, so a component rule more specific than one class still wins: an `isRounded` control stays a pill, and a joined addon keeps its square inner corners.\n\n### Shadowless\n\nShow a Box with `shadowless`:\n\n```tsx live\n
This box has no shadow. \n```\n\n### ClassName\n\nShow a Message with a custom className:\n\n```tsx live\n
\n This message uses a custom className.\n \n```\n\n### Clearfix\n\nShow containers with and without clearfix to demonstrate the importance of clearing floated elements:\n\n```tsx live\n<>\n
\n Without clearfix (container collapses) \n \n \n Left\n \n \n Right\n \n \n \n\n
\n With clearfix (container wraps its floats) \n \n \n Left\n \n \n Right\n \n \n \n>\n```\n\n### Position\n\n`pos` sets CSS `position`: `absolute`, `fixed`, `relative`, `static` or `sticky`. It is named `pos` because several components already have a `position` prop of their own, for where they place a popup or a toast. `relative` is the older shortcut for `pos=\"relative\"` and still works; when both are set, `pos` wins. Beside `overlay`, a `pos` or `relative` replaces the overlay's `absolute` and keeps its zero offsets; see [Overlay](#overlay).\n\nShow a container with relative positioning that provides context for an absolutely positioned child. The helpers set `position` and nothing else, so the child keeps its `top` and `right` offsets inline:\n\n```tsx live\n
\n This container has position: relative \n \n Absolutely positioned child\n \n \n```\n\n`pos=\"sticky\"` needs an offset in the same way, and does nothing until it has one.\n\n### Aspect Ratio\n\n`aspectRatio` fixes an element's width-to-height ratio to one of Bulma's ratios, such as `1by1`, `4by3` or `16by9`, or a portrait one such as `9by16`. The full set is in [Supported Props](#supported-props). The height follows the width:\n\n```tsx live\n
\n \n \n 1by1\n \n \n \n \n 4by3\n \n \n \n \n 16by9\n \n \n \n```\n\nOn `Image`, use its own `size` ratios instead, which also fit the picture to the box.\n\n---\n\n### Skeleton Examples\n\nThe `skeleton` prop applies Bulma's skeleton loading effect. [Skeleton's accessibility notes](../elements/skeleton.md#accessibility) cover it too, reduced motion included. Here are examples for each component:\n\n#### Skeleton Button\n\n```tsx live\n
Skeleton Button \n```\n\n#### Skeleton Buttons Group\n\n```tsx live\n
\n Skeleton \n Skeleton \n Skeleton \n \n```\n\n#### Skeleton Icon\n\n```tsx live\n
\n```\n\n#### Skeleton Image\n\n```tsx live\n
\n```\n\n#### Skeleton Notification\n\n```tsx live\n
Skeleton notification message. \n```\n\n#### Skeleton Tag\n\n```tsx live\n
Skeleton Tag \n```\n\n#### Skeleton Title\n\n```tsx live\n
\n Skeleton Title\n \n```\n\n#### Skeleton SubTitle\n\n```tsx live\n
\n Skeleton SubTitle\n \n```\n\n#### Skeleton Input\n\n```tsx live\n
\n```\n\n#### Skeleton TextArea\n\n```tsx live\n
\n```\n\n---\n\n## API\n\n```tsx\nconst { bulmaHelperClasses, bulmaHelperStyles, rest } = useBulmaClasses(props);\n```\n\n- **props**: An object supporting all Bulma helper class props (see table below), plus any additional props. `backgroundColor` additionally accepts the six [`validSchemeColors`](./valid-values.md) values.\n- **bulmaHelperClasses**: A string of Bulma utility classes to be applied to your element.\n- **bulmaHelperStyles**: `React.CSSProperties | undefined` — an inline style for a scheme `backgroundColor` (see [Scheme Backgrounds](#scheme-backgrounds-and-bulmahelperstyles)); `undefined` for every other input. Apply it with [`mergeBulmaStyles`](#scheme-backgrounds-and-bulmahelperstyles) so a user `style` prop wins.\n- **rest**: An object of all remaining props (with helper props stripped out), suitable for spreading onto your component.\n\n---\n\n## Composable Mini-Hooks\n\n`useBulmaClasses` remains the everything-hook — it is what every bestax-bulma component uses internally, and it covers the full helper prop surface with zero behavior change. If you are building a custom component that only needs a slice of that surface, you can reach for one of seven composable mini hooks instead. Each mini hook accepts just its own group of props and returns a plain class string (except `useColorStyles`, which returns an inline style object or `undefined`), which you can combine with the [`classNames`](./classnames.md) utility.\n\n| Hook | Props Covered | Returns |\n| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `useColorClasses` | `color`, `colorShade`, `backgroundColor`, `backgroundColorShade` | Text and background color classes, including palette shades |\n| `useColorStyles` | `backgroundColor` (scheme values) | `{ backgroundColor: 'var(--bulma-scheme-*)' }` for a scheme background, `undefined` otherwise — the source of `bulmaHelperStyles` |\n| `useSpacingClasses` | `m`, `mt`, `mr`, `mb`, `ml`, `mx`, `my`, `p`, `pt`, `pr`, `pb`, `pl`, `px`, `py`, `gap`, `columnGap`, `rowGap`, `gapless` | Margin, padding and gap classes |\n| `useTypographyClasses` | `textSize`, `textAlign`, `textTransform`, `textWeight`, `fontFamily`, `viewport`, plus `textSize{Mobile..Fullhd}`, `textAlign{Mobile..Fullhd}` | Typography classes, including responsive size/alignment variants |\n| `useVisibilityClasses` | `display`, `visibility`, `viewport`, plus `display{Mobile,Tablet,TabletOnly,Touch,Desktop,DesktopOnly,Widescreen,WidescreenOnly,Fullhd}`, `visibility{Mobile,Tablet,TabletOnly,Touch,Desktop,DesktopOnly,Widescreen,WidescreenOnly,Fullhd}` | Display and visibility classes (this hook owns all display emission) |\n| `useFlexboxClasses` | `flexDirection`, `flexWrap`, `justifyContent`, `alignContent`, `alignItems`, `alignSelf`, `flexGrow`, `flexShrink` | Flexbox classes; container classes are only emitted when a `display`/`display{Viewport}` prop is `flex`/`inline-flex`, item classes (`alignSelf`, `flexGrow`, `flexShrink`) always emit |\n| `useOtherClasses` | `float`, `overflow`, `overflowX`, `overflowY`, `overlay`, `interaction`, `cursor`, `radius`, `shadow`, `responsive`, `skeleton`, `clearfix`, `pos`, `relative`, `fullHeight`, `aspectRatio` | Miscellaneous utility classes |\n\nAll seven hooks (plus `classNames` and `mergeBulmaStyles`) are exported from the package root:\n\n```tsx\nimport {\n useColorClasses,\n useColorStyles,\n useSpacingClasses,\n classNames,\n mergeBulmaStyles,\n} from '@allxsmith/bestax-bulma';\n```\n\nHere is a small custom component that only needs color and spacing helpers:\n\n```tsx live\nimport type { BulmaClassesProps } from '@allxsmith/bestax-bulma';\n\nfunction example() {\n function PriceTag({\n color,\n backgroundColor,\n backgroundColorShade,\n m,\n children,\n }: BulmaClassesProps & { children?: React.ReactNode }) {\n const colorClasses = useColorClasses({\n color,\n backgroundColor,\n backgroundColorShade,\n });\n const spacingClasses = useSpacingClasses({ m });\n return (\n
\n {children}\n \n );\n }\n\n return (\n
\n
\n $19.99\n \n
\n $49.99\n \n
\n );\n}\n```\n\n:::note useFlexboxClasses and display\n\n`useFlexboxClasses` only emits container classes (`flexDirection`, `flexWrap`, `justifyContent`, `alignContent`, `alignItems`) when a `display` or `display{Viewport}` prop is `flex` or `inline-flex` — it reads those display props for gating but never emits the display class itself. Pair it with `useVisibilityClasses` (which owns display emission), or just use `useBulmaClasses`.\n\n:::\n\n---\n\n## Supported Props\n\nBelow is the full list of supported props, derived from the `BulmaClassesProps` TypeScript definition:\n\n| Prop | Type / Example Value | Effect / Example Class |\n| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |\n| `color` | `'primary'`, `'link'`, `'info'`, `'success'`, `'warning'`, `'danger'`, `'black'`, `'black-bis'`, `'black-ter'`, `'grey-darker'`, `'grey-dark'`, `'grey'`, `'grey-light'`, `'grey-lighter'`, `'white'`, `'white-bis'`, `'white-ter'`, `'light'`, `'dark'`, `'inherit'`, `'current'` | `has-text-primary`, `has-text-grey-dark`, `has-text-inherit` |\n| `backgroundColor` | Same as `color`, plus the scheme values `'scheme-main'`, `'scheme-main-bis'`, `'scheme-main-ter'`, `'scheme-invert'`, `'scheme-invert-bis'`, `'scheme-invert-ter'` | `has-background-warning`; scheme values emit no class — they return as the `bulmaHelperStyles` inline style |\n| `colorShade` | `'00'`, `'05'`, `'10'`, `'15'`, `'20'`, `'25'`, `'30'`, `'35'`, `'40'`, `'45'`, `'50'`, `'55'`, `'60'`, `'65'`, `'70'`, `'75'`, `'80'`, `'85'`, `'90'`, `'95'`, `'invert'`, `'light'`, `'dark'`, `'soft'`, `'bold'`, `'on-scheme'` | `has-text-primary-25` |\n| `backgroundColorShade` | `'00'`, `'05'`, `'10'`, `'15'`, `'20'`, `'25'`, `'30'`, `'35'`, `'40'`, `'45'`, `'50'`, `'55'`, `'60'`, `'65'`, `'70'`, `'75'`, `'80'`, `'85'`, `'90'`, `'95'`, `'invert'`, `'light'`, `'dark'`, `'soft'`, `'bold'`, `'on-scheme'` | `has-background-info-dark` |\n| `m` | `'0'..'6'`, `'auto'` | `m-4`, `m-auto` |\n| `mt` | `'0'..'6'`, `'auto'` | `mt-2` |\n| `mr` | `'0'..'6'`, `'auto'` | `mr-6` |\n| `mb` | `'0'..'6'`, `'auto'` | `mb-0` |\n| `ml` | `'0'..'6'`, `'auto'` | `ml-auto` |\n| `mx` | `'0'..'6'`, `'auto'` | `mx-2` |\n| `my` | `'0'..'6'`, `'auto'` | `my-5` |\n| `p` | `'0'..'6'`, `'auto'` | `p-3`, `p-auto` |\n| `pt` | `'0'..'6'`, `'auto'` | `pt-1` |\n| `pr` | `'0'..'6'`, `'auto'` | `pr-6` |\n| `pb` | `'0'..'6'`, `'auto'` | `pb-0` |\n| `pl` | `'0'..'6'`, `'auto'` | `pl-4` |\n| `px` | `'0'..'6'`, `'auto'` | `px-1` |\n| `py` | `'0'..'6'`, `'auto'` | `py-6` |\n| `gap` | `'0'..'8'` in half steps, or a number | `is-gap-1.5` |\n| `columnGap` | Same as `gap` | `is-column-gap-4` |\n| `rowGap` | Same as `gap` | `is-row-gap-0.5` |\n| `gapless` | `true` | `is-gapless` |\n| `textSize` | `'1'..'7'` | `is-size-3` |\n| `textAlign` | `'centered'`, `'justified'`, `'left'`, `'right'` | `has-text-centered` |\n| `textTransform` | `'capitalized'`, `'lowercase'`, `'uppercase'`, `'italic'` | `is-uppercase`, `is-italic` |\n| `textWeight` | `'light'`, `'normal'`, `'medium'`, `'semibold'`, `'bold'` | `has-text-weight-bold` |\n| `fontFamily` | `'sans-serif'`, `'monospace'`, `'primary'`, `'secondary'`, `'code'` | `is-family-monospace` |\n| `display` | `'block'`, `'flex'`, `'inline'`, `'inline-block'`, `'inline-flex'`, `'grid'`, `'none'` | `is-flex`, `is-inline-block`, `is-grid`, `is-hidden` |\n| `visibility` | `'hidden'`, `'sr-only'`, `'invisible'` | `is-hidden`, `is-sr-only`, `is-invisible` |\n| `flexDirection` | `'row'`, `'row-reverse'`, `'column'`, `'column-reverse'` | `is-flex-direction-row` |\n| `flexWrap` | `'nowrap'`, `'wrap'`, `'wrap-reverse'` | `is-flex-wrap-nowrap` |\n| `justifyContent` | `'flex-start'`, `'flex-end'`, `'center'`, `'space-between'`, `'space-around'`, `'space-evenly'`, `'start'`, `'end'`, `'left'`, `'right'` | `is-justify-content-center` |\n| `alignContent` | `'flex-start'`, `'flex-end'`, `'center'`, `'space-between'`, `'space-around'`, `'space-evenly'`, `'stretch'` | `is-align-content-stretch` |\n| `alignItems` | `'stretch'`, `'flex-start'`, `'flex-end'`, `'center'`, `'baseline'`, `'start'`, `'end'` | `is-align-items-center` |\n| `alignSelf` | `'auto'`, `'flex-start'`, `'flex-end'`, `'center'`, `'baseline'`, `'stretch'` | `is-align-self-center` |\n| `flexGrow` | `'0'`, `'1'`, `'2'`, `'3'`, `'4'`, `'5'` | `is-flex-grow-1` |\n| `flexShrink` | `'0'`, `'1'`, `'2'`, `'3'`, `'4'`, `'5'` | `is-flex-shrink-0` |\n| `float` | `'left'`, `'right'` | `is-pulled-left`, `is-pulled-right` |\n| `overflow` | `'clipped'`, `'auto'`, `'clip'`, `'hidden'`, `'scroll'`, `'visible'` | `is-clipped`, `is-overflow-auto` |\n| `overflowX` | `'auto'`, `'clip'`, `'hidden'`, `'scroll'`, `'visible'` | `is-overflow-x-auto` |\n| `overflowY` | `'auto'`, `'clip'`, `'hidden'`, `'scroll'`, `'visible'` | `is-overflow-y-scroll` |\n| `overlay` | `true` | `is-overlay` |\n| `interaction` | `'unselectable'`, `'clickable'` | `is-unselectable` |\n| `cursor` | `'pointer'`, `'help'` | `is-clickable`, `is-cursor-help` |\n| `radius` | `'radiusless'`, `'small'`, `'normal'`, `'large'`, `'rounded'` | `is-radiusless`, `has-radius-large` |\n| `shadow` | `'shadowless'` | `is-shadowless` |\n| `responsive` | `'mobile'`, `'narrow'` | `is-mobile`, `is-narrow` |\n| `viewport` | `'mobile'`, `'tablet'`, `'tablet-only'`, `'touch'`, `'desktop'`, `'desktop-only'`, `'widescreen'`, `'widescreen-only'`, `'fullhd'` | Adds viewport suffix to supported properties |\n| `skeleton` | `true` | `is-skeleton` |\n| `clearfix` | `true` | `is-clearfix` |\n| `pos` | `'absolute'`, `'fixed'`, `'relative'`, `'static'`, `'sticky'` | `is-position-sticky` |\n| `relative` | `true` | `is-relative` (ignored when `pos` is set) |\n| `fullHeight` | `true` | `is-full-height` |\n| `aspectRatio` | `'1by1'`, `'5by4'`, `'4by3'`, `'3by2'`, `'5by3'`, `'16by9'`, `'2by1'`, `'3by1'`, `'4by5'`, `'3by4'`, `'2by3'`, `'3by5'`, `'9by16'`, `'1by2'`, `'1by3'` | `is-aspect-ratio-16by9` |\n\n### Viewport-Specific Properties\n\nThe following properties allow you to set different values for each viewport breakpoint:\n\n| Prop | Type / Example Value | Effect / Example Class |\n| -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |\n| `displayMobile` | `'block'`, `'flex'`, `'inline'`, `'grid'`, `'none'`, etc. | `is-block-mobile`, `is-flex-mobile`, `is-hidden-mobile` |\n| `displayTablet` | Same as above | `is-block-tablet`, `is-flex-tablet`, `is-hidden-tablet` |\n| `displayTabletOnly` | Same as above | `is-block-tablet-only`, `is-flex-tablet-only`, `is-hidden-tablet-only` |\n| `displayTouch` | Same as above | `is-block-touch`, `is-flex-touch`, `is-hidden-touch` |\n| `displayDesktop` | Same as above | `is-block-desktop`, `is-flex-desktop`, `is-hidden-desktop` |\n| `displayDesktopOnly` | Same as above | `is-block-desktop-only`, `is-flex-desktop-only`, `is-hidden-desktop-only` |\n| `displayWidescreen` | Same as above | `is-block-widescreen`, `is-flex-widescreen` |\n| `displayWidescreenOnly` | Same as above | `is-block-widescreen-only`, `is-flex-widescreen-only` |\n| `displayFullhd` | Same as above | `is-block-fullhd`, `is-flex-fullhd` |\n| `textSizeMobile` | `'1'..'7'` | `is-size-3-mobile`, `is-size-5-mobile` |\n| `textSizeTablet` | `'1'..'7'` | `is-size-3-tablet`, `is-size-5-tablet` |\n| `textSizeDesktop` | `'1'..'7'` | `is-size-3-desktop`, `is-size-5-desktop` |\n| `textSizeWidescreen` | `'1'..'7'` | `is-size-3-widescreen`, `is-size-5-widescreen` |\n| `textSizeFullhd` | `'1'..'7'` | `is-size-3-fullhd`, `is-size-5-fullhd` |\n| `textAlignMobile` | `'centered'`, `'left'`, `'right'`, `'justified'` | `has-text-centered-mobile`, `has-text-left-mobile` |\n| `textAlignTablet` | Same as above | `has-text-centered-tablet`, `has-text-left-tablet` |\n| `textAlignDesktop` | Same as above | `has-text-centered-desktop`, `has-text-left-desktop` |\n| `textAlignWidescreen` | Same as above | `has-text-centered-widescreen`, `has-text-left-widescreen` |\n| `textAlignFullhd` | Same as above | `has-text-centered-fullhd`, `has-text-left-fullhd` |\n| `visibilityMobile` | `'hidden'`, `'sr-only'`, `'invisible'` | `is-hidden-mobile`, `is-sr-only-mobile`, `is-invisible-mobile` |\n| `visibilityTablet` | Same as above | `is-hidden-tablet`, `is-sr-only-tablet`, `is-invisible-tablet` |\n| `visibilityTabletOnly` | Same as above | `is-hidden-tablet-only`, `is-sr-only-tablet-only`, `is-invisible-tablet-only` |\n| `visibilityTouch` | Same as above | `is-hidden-touch`, `is-sr-only-touch`, `is-invisible-touch` |\n| `visibilityDesktop` | Same as above | `is-hidden-desktop`, `is-sr-only-desktop`, `is-invisible-desktop` |\n| `visibilityDesktopOnly` | Same as above | `is-hidden-desktop-only`, `is-sr-only-desktop-only`, `is-invisible-desktop-only` |\n| `visibilityWidescreen` | Same as above | `is-hidden-widescreen`, `is-sr-only-widescreen`, `is-invisible-widescreen` |\n| `visibilityWidescreenOnly` | Same as above | `is-hidden-widescreen-only`, `is-sr-only-widescreen-only`, `is-invisible-widescreen-only` |\n| `visibilityFullhd` | Same as above | `is-hidden-fullhd`, `is-sr-only-fullhd`, `is-invisible-fullhd` |\n| `responsive` | `'mobile'`, `'narrow'` | `is-mobile`, `is-narrow` |\n| `clearfix` | `true` | `is-clearfix` |\n| `relative` | `true` | `is-relative` |\n| `viewport` | `'mobile'`, `'tablet'`, `'tablet-only'`, `'touch'`, `'desktop'`, `'desktop-only'`, `'widescreen'`, `'widescreen-only'`, `'fullhd'` | Adds suffix, e.g. `-mobile`, `-desktop`, `-touch`, `-tablet-only` |\n\n---\n\n### Full TypeScript Definition\n\n`BulmaClassesProps` is composed from the six group interfaces, each of which is also exported (along with the shared `BulmaViewportProps` and `BulmaDisplayProps` types) and accepted by the corresponding [mini hook](#composable-mini-hooks). The hook's parameter is the widened `BulmaClassesPropsWithScheme` — identical to `BulmaClassesProps` except that `backgroundColor` also accepts the six `validSchemeColors` values (`BulmaColorPropsWithScheme` is the color-group equivalent, accepted by `useColorClasses` and `useColorStyles`):\n\n```ts\nexport interface BulmaClassesProps\n extends\n BulmaColorProps,\n BulmaSpacingProps,\n BulmaTypographyProps,\n BulmaVisibilityProps,\n BulmaFlexboxProps,\n BulmaOtherProps {}\n\nexport type BulmaViewportProps =\n | 'mobile'\n | 'tablet'\n | 'tablet-only'\n | 'touch'\n | 'desktop'\n | 'desktop-only'\n | 'widescreen'\n | 'widescreen-only'\n | 'fullhd';\n\nexport type BulmaDisplayProps =\n | 'block'\n | 'flex'\n | 'inline'\n | 'inline-block'\n | 'inline-flex'\n | 'grid'\n | 'none';\n\nexport interface BulmaColorProps {\n color?:\n | 'primary'\n | 'link'\n | 'info'\n | 'success'\n | 'warning'\n | 'danger'\n | 'black'\n | 'black-bis'\n | 'black-ter'\n | 'grey-darker'\n | 'grey-dark'\n | 'grey'\n | 'grey-light'\n | 'grey-lighter'\n | 'white'\n | 'white-bis'\n | 'white-ter'\n | 'light'\n | 'dark'\n | 'inherit'\n | 'current';\n colorShade?:\n | '00'\n | '05'\n | '10'\n | '15'\n | '20'\n | '25'\n | '30'\n | '35'\n | '40'\n | '45'\n | '50'\n | '55'\n | '60'\n | '65'\n | '70'\n | '75'\n | '80'\n | '85'\n | '90'\n | '95'\n | 'invert'\n | 'light'\n | 'dark'\n | 'soft'\n | 'bold'\n | 'on-scheme';\n backgroundColor?: BulmaColorProps['color'];\n backgroundColorShade?: BulmaColorProps['colorShade'];\n}\n\n// The scheme-aware input accepted by useBulmaClasses, useColorClasses,\n// and useColorStyles ((typeof validSchemeColors)[number] is\n// 'scheme-main' | 'scheme-main-bis' | 'scheme-main-ter'\n// | 'scheme-invert' | 'scheme-invert-bis' | 'scheme-invert-ter'):\nexport type BulmaColorPropsWithScheme = Omit<\n BulmaColorProps,\n 'backgroundColor'\n> & {\n backgroundColor?:\n BulmaColorProps['backgroundColor'] | (typeof validSchemeColors)[number];\n};\n\nexport type BulmaClassesPropsWithScheme = Omit<\n BulmaClassesProps,\n keyof BulmaColorProps\n> &\n BulmaColorPropsWithScheme;\n\nexport interface BulmaSpacingProps {\n m?: '0' | '1' | '2' | '3' | '4' | '5' | '6' | 'auto';\n mt?: '0' | '1' | '2' | '3' | '4' | '5' | '6' | 'auto';\n mr?: '0' | '1' | '2' | '3' | '4' | '5' | '6' | 'auto';\n mb?: '0' | '1' | '2' | '3' | '4' | '5' | '6' | 'auto';\n ml?: '0' | '1' | '2' | '3' | '4' | '5' | '6' | 'auto';\n mx?: '0' | '1' | '2' | '3' | '4' | '5' | '6' | 'auto';\n my?: '0' | '1' | '2' | '3' | '4' | '5' | '6' | 'auto';\n p?: '0' | '1' | '2' | '3' | '4' | '5' | '6' | 'auto';\n pt?: '0' | '1' | '2' | '3' | '4' | '5' | '6' | 'auto';\n pr?: '0' | '1' | '2' | '3' | '4' | '5' | '6' | 'auto';\n pb?: '0' | '1' | '2' | '3' | '4' | '5' | '6' | 'auto';\n pl?: '0' | '1' | '2' | '3' | '4' | '5' | '6' | 'auto';\n px?: '0' | '1' | '2' | '3' | '4' | '5' | '6' | 'auto';\n py?: '0' | '1' | '2' | '3' | '4' | '5' | '6' | 'auto';\n gap?: BulmaGapStep;\n columnGap?: BulmaGapStep;\n rowGap?: BulmaGapStep;\n gapless?: boolean;\n}\n\n// '0' to '8' in half steps ('0', '0.5', '1', … '7.5', '8'), as strings or numbers\nexport type BulmaGapStep =\n | '0'\n | '0.5'\n | '1'\n | '1.5'\n | '2'\n | '2.5'\n | '3'\n | '3.5'\n | '4'\n | '4.5'\n | '5'\n | '5.5'\n | '6'\n | '6.5'\n | '7'\n | '7.5'\n | '8'\n | 0\n | 0.5\n | 1\n | 1.5\n | 2\n | 2.5\n | 3\n | 3.5\n | 4\n | 4.5\n | 5\n | 5.5\n | 6\n | 6.5\n | 7\n | 7.5\n | 8;\n\nexport interface BulmaTypographyProps {\n textSize?: '1' | '2' | '3' | '4' | '5' | '6' | '7';\n textAlign?: 'centered' | 'justified' | 'left' | 'right';\n textTransform?: 'capitalized' | 'lowercase' | 'uppercase' | 'italic';\n textWeight?: 'light' | 'normal' | 'medium' | 'semibold' | 'bold';\n fontFamily?: 'sans-serif' | 'monospace' | 'primary' | 'secondary' | 'code';\n viewport?: BulmaViewportProps;\n textSizeMobile?: '1' | '2' | '3' | '4' | '5' | '6' | '7';\n textSizeTablet?: '1' | '2' | '3' | '4' | '5' | '6' | '7';\n textSizeDesktop?: '1' | '2' | '3' | '4' | '5' | '6' | '7';\n textSizeWidescreen?: '1' | '2' | '3' | '4' | '5' | '6' | '7';\n textSizeFullhd?: '1' | '2' | '3' | '4' | '5' | '6' | '7';\n textAlignMobile?: 'centered' | 'justified' | 'left' | 'right';\n textAlignTablet?: 'centered' | 'justified' | 'left' | 'right';\n textAlignDesktop?: 'centered' | 'justified' | 'left' | 'right';\n textAlignWidescreen?: 'centered' | 'justified' | 'left' | 'right';\n textAlignFullhd?: 'centered' | 'justified' | 'left' | 'right';\n}\n\nexport interface BulmaVisibilityProps {\n display?: BulmaDisplayProps;\n visibility?: 'hidden' | 'sr-only' | 'invisible';\n viewport?: BulmaViewportProps;\n displayMobile?: BulmaDisplayProps;\n displayTablet?: BulmaDisplayProps;\n displayTabletOnly?: BulmaDisplayProps;\n displayTouch?: BulmaDisplayProps;\n displayDesktop?: BulmaDisplayProps;\n displayDesktopOnly?: BulmaDisplayProps;\n displayWidescreen?: BulmaDisplayProps;\n displayWidescreenOnly?: BulmaDisplayProps;\n displayFullhd?: BulmaDisplayProps;\n visibilityMobile?: 'hidden' | 'sr-only' | 'invisible';\n visibilityTablet?: 'hidden' | 'sr-only' | 'invisible';\n visibilityTabletOnly?: 'hidden' | 'sr-only' | 'invisible';\n visibilityTouch?: 'hidden' | 'sr-only' | 'invisible';\n visibilityDesktop?: 'hidden' | 'sr-only' | 'invisible';\n visibilityDesktopOnly?: 'hidden' | 'sr-only' | 'invisible';\n visibilityWidescreen?: 'hidden' | 'sr-only' | 'invisible';\n visibilityWidescreenOnly?: 'hidden' | 'sr-only' | 'invisible';\n visibilityFullhd?: 'hidden' | 'sr-only' | 'invisible';\n}\n\nexport interface BulmaFlexboxProps {\n flexDirection?: 'row' | 'row-reverse' | 'column' | 'column-reverse';\n flexWrap?: 'nowrap' | 'wrap' | 'wrap-reverse';\n justifyContent?:\n | 'flex-start'\n | 'flex-end'\n | 'center'\n | 'space-between'\n | 'space-around'\n | 'space-evenly'\n | 'start'\n | 'end'\n | 'left'\n | 'right';\n alignContent?:\n | 'flex-start'\n | 'flex-end'\n | 'center'\n | 'space-between'\n | 'space-around'\n | 'space-evenly'\n | 'stretch';\n alignItems?:\n | 'stretch'\n | 'flex-start'\n | 'flex-end'\n | 'center'\n | 'baseline'\n | 'start'\n | 'end';\n alignSelf?:\n 'auto' | 'flex-start' | 'flex-end' | 'center' | 'baseline' | 'stretch';\n flexGrow?: '0' | '1' | '2' | '3' | '4' | '5';\n flexShrink?: '0' | '1' | '2' | '3' | '4' | '5';\n}\n\nexport interface BulmaOtherProps {\n float?: 'left' | 'right';\n overflow?: 'clipped' | 'auto' | 'clip' | 'hidden' | 'scroll' | 'visible';\n overflowX?: 'auto' | 'clip' | 'hidden' | 'scroll' | 'visible';\n overflowY?: 'auto' | 'clip' | 'hidden' | 'scroll' | 'visible';\n overlay?: boolean;\n interaction?: 'unselectable' | 'clickable';\n cursor?: 'pointer' | 'help';\n radius?: 'radiusless' | 'small' | 'normal' | 'large' | 'rounded';\n shadow?: 'shadowless';\n responsive?: 'mobile' | 'narrow';\n skeleton?: boolean;\n clearfix?: boolean;\n pos?: 'absolute' | 'fixed' | 'relative' | 'static' | 'sticky';\n relative?: boolean;\n fullHeight?: boolean;\n aspectRatio?:\n | '1by1'\n | '5by4'\n | '4by3'\n | '3by2'\n | '5by3'\n | '16by9'\n | '2by1'\n | '3by1'\n | '4by5'\n | '3by4'\n | '2by3'\n | '3by5'\n | '9by16'\n | '1by2'\n | '1by3';\n}\n```\n\n---\n\n## Responsive Design\n\n### Global Viewport Property (Legacy)\n\nThe `viewport` prop applies a single viewport modifier to ALL properties that support it:\n\n```tsx\nconst { bulmaHelperClasses } = useBulmaClasses({\n color: 'primary',\n textAlign: 'centered',\n textSize: '4',\n viewport: 'mobile', // Applies -mobile to ALL properties\n});\n// Result: has-text-primary-mobile has-text-centered-mobile is-size-4-mobile\n```\n\n### Viewport-Specific Properties (Recommended)\n\nViewport-specific properties allow you to set **different values for each viewport**:\n\n```tsx\nconst { bulmaHelperClasses } = useBulmaClasses({\n // Different text sizes for each viewport\n textSizeMobile: '6', // Small on mobile\n textSizeTablet: '5', // Medium on tablet\n textSizeDesktop: '4', // Large on desktop\n\n // Different text alignment for each viewport\n textAlignMobile: 'centered', // Center on mobile\n textAlignDesktop: 'left', // Left align on desktop\n\n // Different visibility for each viewport\n visibilityMobile: 'hidden', // Hidden on mobile\n visibilityTablet: 'invisible', // Invisible on tablet\n});\n// Result: is-size-6-mobile is-size-5-tablet is-size-4-desktop\n// has-text-centered-mobile has-text-left-desktop is-hidden-mobile is-invisible-tablet\n```\n\n### Breakpoint Reference\n\nBulma's responsive breakpoints:\n\n- **mobile**: up to 768px\n- **tablet**: 769px and above\n- **tablet-only**: 769px - 1023px (excludes desktop and above)\n- **touch**: up to 1023px (mobile + tablet combined — the breakpoint most often used to hide desktop-only chrome)\n- **desktop**: 1024px and above\n- **desktop-only**: 1024px - 1215px (excludes widescreen and above)\n- **widescreen**: 1216px and above\n- **widescreen-only**: 1216px - 1407px (excludes fullhd)\n- **fullhd**: 1408px and above\n\n`display`/`visibility` are the only property families with `*Touch`/`*TabletOnly`/`*DesktopOnly`/`*WidescreenOnly` props; other viewport-aware properties (`textSize*`, `textAlign*`) only go through `mobile`/`tablet`/`desktop`/`widescreen`/`fullhd`, though the generic `viewport` prop itself accepts all nine values for any property that reads it.\n\n### Properties That Support Viewport Modifiers\n\nOnly certain properties support responsive variants:\n\n**✅ Support Viewport Modifiers:**\n\n- Text size (`textSize`, `textSizeMobile`, `textSizeTablet`, etc.)\n- Text alignment (`textAlign`, `textAlignMobile`, `textAlignTablet`, etc.)\n- Display (`display`, `displayMobile`, `displayTablet`, `displayTabletOnly`, `displayTouch`, `displayDesktop`, `displayDesktopOnly`, `displayWidescreen`, `displayWidescreenOnly`, `displayFullhd`)\n- Visibility (`visibility`, `visibilityMobile`, `visibilityTablet`, `visibilityTabletOnly`, `visibilityTouch`, `visibilityDesktop`, `visibilityDesktopOnly`, `visibilityWidescreen`, `visibilityWidescreenOnly`, `visibilityFullhd`)\n\n**❌ Do NOT Support Viewport Modifiers:**\n\n- Spacing (`m`, `mt`, `mr`, `mb`, `ml`, `mx`, `my`, `p`, `pt`, `pr`, `pb`, `pl`, `px`, `py`)\n- Background colors (`backgroundColor`)\n- Flexbox properties (`flexDirection`, `flexWrap`, `justifyContent`, etc.)\n- Other helpers (`float`, `overflow`, `pos`, `radius`, `shadow`, `aspectRatio`, etc.)\n\n---\n\n## Notes\n\n- Any prop not recognized as a Bulma helper prop is passed through in `rest`.\n- Responsive helper props (`viewport`) suffix classes with the breakpoint (e.g., `is-size-3-mobile`).\n- You can use in combination with [`classNames`](./classnames.md) for more advanced use.\n\n---\n\n## See Also\n\n- [classNames helper](./classnames.md)\n- [Bulma Classes Reference](https://bulma.io/documentation/helpers/)\n- [Storybook: useBulmaClasses Demo](https://bestax.io/storybook/?path=/story/helpers-usebulmaclasses--default)",
"parts": [],
"cssVars": []
}
diff --git a/docs/docs/api/components/avatar.md b/docs/docs/api/components/avatar.md
index df823b278..4add469be 100644
--- a/docs/docs/api/components/avatar.md
+++ b/docs/docs/api/components/avatar.md
@@ -135,8 +135,8 @@ automatic initials/icon fallback runs.
```tsx live
function example() {
- const avatarRef = React.useRef(null);
- const [tag, setTag] = React.useState(null);
+ const avatarRef = React.useRef
(null);
+ const [tag, setTag] = React.useState();
return (
<>
diff --git a/docs/docs/api/components/carousel.md b/docs/docs/api/components/carousel.md
index 48baae12f..f7031e3fe 100644
--- a/docs/docs/api/components/carousel.md
+++ b/docs/docs/api/components/carousel.md
@@ -102,7 +102,9 @@ Different indicator style options.
```tsx live
function IndicatorExample() {
- const [style, setStyle] = useState('dots');
+ const [style, setStyle] = useState<'dots' | 'circles' | 'lines' | 'bars'>(
+ 'dots'
+ );
return (
diff --git a/docs/docs/api/components/collapse.md b/docs/docs/api/components/collapse.md
index ef1ec4b3b..7ea5ccf43 100644
--- a/docs/docs/api/components/collapse.md
+++ b/docs/docs/api/components/collapse.md
@@ -40,13 +40,9 @@ A simple uncontrolled collapse.
function example() {
return (
+
Click to expand
}
@@ -72,14 +68,10 @@ Collapse that starts open by default.
function example() {
return (
+
This starts open
}
@@ -102,14 +94,10 @@ Collapse that toggles instantly without animation.
function example() {
return (
+
No animation
}
@@ -143,10 +131,11 @@ function example() {
State: {isOpen ? 'Open' : 'Closed'}
+
Controlled collapse (click here or the button above)
}
diff --git a/docs/docs/api/components/dialog.md b/docs/docs/api/components/dialog.md
index fc931cdc9..20364ffa8 100644
--- a/docs/docs/api/components/dialog.md
+++ b/docs/docs/api/components/dialog.md
@@ -102,7 +102,9 @@ Different dialog types with matching icons.
```tsx live
function example() {
- const [dialogType, setDialogType] = useState(null);
+ const [dialogType, setDialogType] = useState<
+ 'success' | 'danger' | 'warning' | 'info' | null
+ >(null);
return (
diff --git a/docs/docs/api/components/dropdown.md b/docs/docs/api/components/dropdown.md
index a0e01154f..7f9acaf1e 100644
--- a/docs/docs/api/components/dropdown.md
+++ b/docs/docs/api/components/dropdown.md
@@ -153,8 +153,8 @@ function example() {
```tsx live
function example() {
- const dropdownRef = React.useRef(null);
- const [tag, setTag] = React.useState(null);
+ const dropdownRef = React.useRef(null);
+ const [tag, setTag] = React.useState();
return (
<>
diff --git a/docs/docs/api/components/menu.md b/docs/docs/api/components/menu.md
index cc410ae5b..09f23df4e 100644
--- a/docs/docs/api/components/menu.md
+++ b/docs/docs/api/components/menu.md
@@ -80,7 +80,9 @@ Use the `as` prop on `Menu.Item` to render a custom link component, such as a ro
```tsx live
// import { Link } from 'react-router-dom';
function example() {
- const Link = props => {props.children} ;
+ const Link = (props: { to: string; children?: React.ReactNode }) => (
+ {props.children}
+ );
return (
App
@@ -147,7 +149,7 @@ Create multi-level navigation by nesting `Menu.List` components inside `Menu.Ite
```tsx live
function example() {
- const itemRef = React.useRef(null);
+ const itemRef = React.useRef(null);
return (
<>
diff --git a/docs/docs/api/components/modal.md b/docs/docs/api/components/modal.md
index c51449ddc..5f951a3e9 100644
--- a/docs/docs/api/components/modal.md
+++ b/docs/docs/api/components/modal.md
@@ -240,8 +240,8 @@ It's SSR-safe: a portal has no server-rendered counterpart, so the modal renders
```tsx live
function example() {
const [open, setOpen] = React.useState(false);
- const [width, setWidth] = React.useState(null);
- const modalRef = React.useRef(null);
+ const [width, setWidth] = React.useState(null);
+ const modalRef = React.useRef(null);
return (
<>
diff --git a/docs/docs/api/components/navbar.md b/docs/docs/api/components/navbar.md
index 12ae927fe..faffad43a 100644
--- a/docs/docs/api/components/navbar.md
+++ b/docs/docs/api/components/navbar.md
@@ -186,7 +186,9 @@ Use the `as` prop on `Navbar.Item` to render a custom link component, such as a
```tsx live
// import { Link } from 'react-router-dom';
function example() {
- const Link = props => {props.children} ;
+ const Link = (props: { to: string; children?: React.ReactNode }) => (
+ {props.children}
+ );
return (
@@ -363,7 +365,7 @@ function example() {
'dark',
'light',
'white',
- ];
+ ] as const;
return (
<>
{colors.map(color => (
@@ -395,8 +397,8 @@ function example() {
```tsx live
function example() {
- const navRef = React.useRef(null);
- const [height, setHeight] = React.useState(null);
+ const navRef = React.useRef(null);
+ const [height, setHeight] = React.useState();
return (
<>
diff --git a/docs/docs/api/components/panel.md b/docs/docs/api/components/panel.md
index 7504b16c6..1368aaa62 100644
--- a/docs/docs/api/components/panel.md
+++ b/docs/docs/api/components/panel.md
@@ -92,18 +92,20 @@ This example demonstrates the `Panel` component's color variants. The `color` pr
```tsx live
<>
- {[
- 'primary',
- 'link',
- 'info',
- 'success',
- 'warning',
- 'danger',
- 'black',
- 'dark',
- 'light',
- 'white',
- ].map(color => (
+ {(
+ [
+ 'primary',
+ 'link',
+ 'info',
+ 'success',
+ 'warning',
+ 'danger',
+ 'black',
+ 'dark',
+ 'light',
+ 'white',
+ ] as const
+ ).map(color => (
{color.charAt(0).toUpperCase() + color.slice(1)} Panel
diff --git a/docs/docs/api/components/toast.md b/docs/docs/api/components/toast.md
index c9a380121..ce70a3d20 100644
--- a/docs/docs/api/components/toast.md
+++ b/docs/docs/api/components/toast.md
@@ -69,7 +69,9 @@ function example() {
```tsx live
function example() {
- const [toastType, setToastType] = useState(null);
+ const [toastType, setToastType] = useState<
+ 'success' | 'danger' | 'warning' | 'info' | null
+ >(null);
return (
@@ -107,9 +109,11 @@ function example() {
Toast can appear in any of six positions. (The `transform` on the wrapper is a docs-only trick that scopes the toast's `position: fixed` to the example box; in your app, omit the wrapper.)
```tsx live
+import type { ToastPosition } from '@allxsmith/bestax-bulma';
+
function example() {
- const [position, setPosition] = useState(null);
- const [box, setBox] = useState(null);
+ const [position, setPosition] = useState(null);
+ const [box, setBox] = useState(null);
return (
- {['primary', 'link', 'info', 'success', 'warning', 'danger'].map(color => (
-
- {color.charAt(0).toUpperCase() + color.slice(1)}
-
- ))}
+ {(['primary', 'link', 'info', 'success', 'warning', 'danger'] as const).map(
+ color => (
+
+ {color.charAt(0).toUpperCase() + color.slice(1)}
+
+ )
+ )}
```
@@ -68,7 +70,7 @@ The `size` prop lets you adjust the button’s scale for various contexts. Suppo
```tsx live
- {['small', 'normal', 'medium', 'large'].map(size => (
+ {(['small', 'normal', 'medium', 'large'] as const).map(size => (
{size.charAt(0).toUpperCase() + size.slice(1)}
@@ -291,8 +293,8 @@ The props follow `as`, so the type checker already limits what you can pass to w
```tsx live
function example() {
- const buttonRef = React.useRef(null);
- const [tag, setTag] = React.useState(null);
+ const buttonRef = React.useRef(null);
+ const [tag, setTag] = React.useState();
return (
<>
diff --git a/docs/docs/api/elements/buttons.md b/docs/docs/api/elements/buttons.md
index dc9fad4f9..d03547e97 100644
--- a/docs/docs/api/elements/buttons.md
+++ b/docs/docs/api/elements/buttons.md
@@ -54,11 +54,13 @@ This example shows a group of buttons, each with a different `color` prop (`prim
```tsx live
- {['primary', 'link', 'info', 'success', 'warning', 'danger'].map(color => (
-
- {color.charAt(0).toUpperCase() + color.slice(1)}
-
- ))}
+ {(['primary', 'link', 'info', 'success', 'warning', 'danger'] as const).map(
+ color => (
+
+ {color.charAt(0).toUpperCase() + color.slice(1)}
+
+ )
+ )}
```
@@ -68,7 +70,7 @@ Demonstrates a group of buttons with different `size` props (`small`, `normal`,
```tsx live
- {['small', 'normal', 'medium', 'large'].map(size => (
+ {(['small', 'normal', 'medium', 'large'] as const).map(size => (
{size.charAt(0).toUpperCase() + size.slice(1)}
diff --git a/docs/docs/api/elements/link.md b/docs/docs/api/elements/link.md
index d4ad4a8de..9a75a046a 100644
--- a/docs/docs/api/elements/link.md
+++ b/docs/docs/api/elements/link.md
@@ -179,8 +179,8 @@ Links work seamlessly inline within text content.
```tsx live
function example() {
- const linkRef = React.useRef(null);
- const [tag, setTag] = React.useState(null);
+ const linkRef = React.useRef(null);
+ const [tag, setTag] = React.useState();
return (
<>
diff --git a/docs/docs/api/elements/linkbutton.md b/docs/docs/api/elements/linkbutton.md
index 44b8982b2..7f8256472 100644
--- a/docs/docs/api/elements/linkbutton.md
+++ b/docs/docs/api/elements/linkbutton.md
@@ -90,11 +90,13 @@ Colors work with the ghost variant too.
```tsx live
- {['primary', 'link', 'info', 'success', 'warning', 'danger'].map(color => (
-
- {color.charAt(0).toUpperCase() + color.slice(1)}
-
- ))}
+ {(['primary', 'link', 'info', 'success', 'warning', 'danger'] as const).map(
+ color => (
+
+ {color.charAt(0).toUpperCase() + color.slice(1)}
+
+ )
+ )}
```
@@ -110,7 +112,7 @@ Colors work with the ghost variant too.
```tsx live
- {['small', 'normal', 'medium', 'large'].map(size => (
+ {(['small', 'normal', 'medium', 'large'] as const).map(size => (
{size.charAt(0).toUpperCase() + size.slice(1)}
@@ -139,9 +141,9 @@ import { LinkButton } from '@allxsmith/bestax-bulma';
```tsx live
function example() {
- const defaultRef = React.useRef(null);
- const anchorRef = React.useRef(null);
- const [tags, setTags] = React.useState(null);
+ const defaultRef = React.useRef(null);
+ const anchorRef = React.useRef(null);
+ const [tags, setTags] = React.useState();
return (
<>
diff --git a/docs/docs/api/elements/subtitle.md b/docs/docs/api/elements/subtitle.md
index 90c688e81..fb2099955 100644
--- a/docs/docs/api/elements/subtitle.md
+++ b/docs/docs/api/elements/subtitle.md
@@ -99,7 +99,7 @@ Quickly render all subtitle sizes from `1` to `6` using a map function. This is
```tsx live
<>
- {['1', '2', '3', '4', '5', '6'].map(size => (
+ {(['1', '2', '3', '4', '5', '6'] as const).map(size => (
SubTitle Size {size}
diff --git a/docs/docs/api/elements/tag.md b/docs/docs/api/elements/tag.md
index fe874d673..75994e68d 100644
--- a/docs/docs/api/elements/tag.md
+++ b/docs/docs/api/elements/tag.md
@@ -118,18 +118,20 @@ Render a set of tags with different `color` values to display a palette of avail
```tsx live
- {[
- 'primary',
- 'link',
- 'info',
- 'success',
- 'warning',
- 'danger',
- 'black',
- 'dark',
- 'light',
- 'white',
- ].map(color => (
+ {(
+ [
+ 'primary',
+ 'link',
+ 'info',
+ 'success',
+ 'warning',
+ 'danger',
+ 'black',
+ 'dark',
+ 'light',
+ 'white',
+ ] as const
+ ).map(color => (
{color.charAt(0).toUpperCase() + color.slice(1)}
@@ -143,7 +145,7 @@ You can combine `color`, `size`, and `isHoverable` props to show all size varian
```tsx live
- {['primary', 'success', 'danger'].map(color => (
+ {(['primary', 'success', 'danger'] as const).map(color => (
{color.charAt(0).toUpperCase() + color.slice(1)} Normal
diff --git a/docs/docs/api/elements/tags.md b/docs/docs/api/elements/tags.md
index d5e9a4971..d6db9883c 100644
--- a/docs/docs/api/elements/tags.md
+++ b/docs/docs/api/elements/tags.md
@@ -107,7 +107,7 @@ Combine props such as `size`, `isRounded`, and `isDelete` to create flexible, in
```tsx live
function example() {
- const [show, setShow] = useState();
+ const [show, setShow] = useState(true);
return (
diff --git a/docs/docs/api/elements/title.md b/docs/docs/api/elements/title.md
index cedea1c49..be8d9e86c 100644
--- a/docs/docs/api/elements/title.md
+++ b/docs/docs/api/elements/title.md
@@ -107,7 +107,7 @@ Quickly render titles of all sizes from `1` to `6` using a map function. This is
```tsx live
<>
- {['1', '2', '3', '4', '5', '6'].map(size => (
+ {(['1', '2', '3', '4', '5', '6'] as const).map(size => (
Title Size {size}
diff --git a/docs/docs/api/form/autocomplete.md b/docs/docs/api/form/autocomplete.md
index fee91035e..1856c5e47 100644
--- a/docs/docs/api/form/autocomplete.md
+++ b/docs/docs/api/form/autocomplete.md
@@ -34,11 +34,11 @@ import { Autocomplete } from '@allxsmith/bestax-bulma';
### Basic Autocomplete
-Simple autocomplete with string array.
+Simple autocomplete with string array. `onSelect` is typed for either kind of `data`, as `string | AutocompleteItem | null`, so narrow the item to the kind you passed before storing it.
```tsx live
function example() {
- const [selected, setSelected] = useState(null);
+ const [selected, setSelected] = useState(null);
const fruits = [
'Apple',
'Banana',
@@ -54,7 +54,7 @@ function example() {
setSelected(typeof item === 'string' ? item : null)}
/>
{selected && Selected: {selected} }
@@ -70,7 +70,6 @@ Dropdown opens immediately when input is focused.
```tsx live
function example() {
- const [selected, setSelected] = useState(null);
const countries = [
'United States',
'United Kingdom',
@@ -85,7 +84,6 @@ function example() {
data={countries}
placeholder="Select a country..."
openOnFocus
- onSelect={setSelected}
/>
);
}
@@ -99,16 +97,10 @@ Autocomplete with clearable input. The clear button shows while the input holds
```tsx live
function example() {
- const [selected, setSelected] = useState(null);
const options = ['Option 1', 'Option 2', 'Option 3', 'Option 4'];
return (
-
+
);
}
```
@@ -151,16 +143,16 @@ Autocomplete with different colors and sizes.
### With Object Data
-Autocomplete with object items.
+Autocomplete with object items. `onSelect` passes back the item you picked, so looking it up in your own array by its `value` gives it back with your fields typed.
```tsx live
function example() {
- const [selected, setSelected] = useState(null);
const users = [
{ value: '1', label: 'John Doe', email: 'john@example.com' },
{ value: '2', label: 'Jane Smith', email: 'jane@example.com' },
{ value: '3', label: 'Bob Johnson', email: 'bob@example.com' },
];
+ const [selected, setSelected] = useState<(typeof users)[number] | null>(null);
return (
@@ -169,7 +161,13 @@ function example() {
field="label"
placeholder="Search users..."
openOnFocus
- onSelect={setSelected}
+ onSelect={item =>
+ setSelected(
+ users.find(
+ u => u.value === (typeof item === 'string' ? item : item?.value)
+ ) ?? null
+ )
+ }
/>
{selected && (
@@ -185,11 +183,10 @@ function example() {
### Custom Item Template
-Autocomplete with custom item rendering.
+Autocomplete with custom item rendering. `itemTemplate` receives each item the same way, so the template looks it up by `value` too.
```tsx live
function example() {
- const [selected, setSelected] = useState(null);
const users = [
{ value: '1', label: 'John Doe', role: 'Admin' },
{ value: '2', label: 'Jane Smith', role: 'Editor' },
@@ -202,15 +199,19 @@ function example() {
field="label"
placeholder="Search users..."
openOnFocus
- onSelect={setSelected}
- itemTemplate={item => (
-
- {item.label}
-
- {item.role}
-
-
- )}
+ itemTemplate={item => {
+ const user = users.find(
+ u => u.value === (typeof item === 'string' ? item : item.value)
+ );
+ return (
+
+ {user?.label}
+
+ {user?.role}
+
+
+ );
+ }}
/>
);
}
diff --git a/docs/docs/api/form/checkboxes.md b/docs/docs/api/form/checkboxes.md
index 18ae3acd4..38b74d6e2 100644
--- a/docs/docs/api/form/checkboxes.md
+++ b/docs/docs/api/form/checkboxes.md
@@ -171,7 +171,7 @@ function ControlledCheckboxes() {
```tsx live
function UncontrolledCheckboxes() {
- const [latest, setLatest] = React.useState([]);
+ const [latest, setLatest] = React.useState([]);
return (
(new Date());
return (
@@ -80,7 +80,7 @@ function example() {
```tsx live
function example() {
- const [value, setValue] = useState(new Date());
+ const [value, setValue] = useState(new Date());
return (
{
+ const parse = (s: string) => {
const t = Date.parse(s);
return isNaN(t) ? null : new Date(t);
};
@@ -344,7 +344,7 @@ function example() {
```tsx live
function example() {
- const parse = s => {
+ const parse = (s: string) => {
const t = Date.parse(s);
return isNaN(t) ? null : new Date(t);
};
@@ -455,7 +455,7 @@ function example() {
```tsx live
function example() {
- const [v, setV] = useState(() => new Date(2024, 5, 7));
+ const [v, setV] = useState(() => new Date(2024, 5, 7));
return (
([null, null]);
const [start, end] = range;
return (
@@ -104,7 +106,7 @@ function NextMonth() {
```tsx live
function Weekdays() {
- const weekend = d => d.getDay() === 0 || d.getDay() === 6;
+ const weekend = (d: Date) => d.getDay() === 0 || d.getDay() === 6;
return (
diff --git a/docs/docs/api/form/datetime/datetimeinput.md b/docs/docs/api/form/datetime/datetimeinput.md
index e9b004bc4..c15f9c72b 100644
--- a/docs/docs/api/form/datetime/datetimeinput.md
+++ b/docs/docs/api/form/datetime/datetimeinput.md
@@ -56,7 +56,7 @@ The popover opens to the calendar with an iOS-style footer — the selected time
```tsx live
function example() {
- const [v, setV] = useState(new Date());
+ const [v, setV] = useState(new Date());
return (
@@ -70,7 +70,7 @@ function example() {
```tsx live
function example() {
- const [v, setV] = useState(new Date());
+ const [v, setV] = useState(new Date());
return (
new Date(2024, 5, 7, 13, 45));
+ const [v, setV] = useState(() => new Date(2024, 5, 7, 13, 45));
return (
{
+ const [v, setV] = useState(() => {
const d = new Date();
d.setHours(13, 45, 0, 0);
return d;
@@ -68,7 +68,7 @@ function example() {
```tsx live
function example() {
- const [v, setV] = useState(() => {
+ const [v, setV] = useState(() => {
const d = new Date();
d.setHours(13, 45, 0, 0);
return d;
@@ -294,7 +294,7 @@ On iOS Safari the picker UI lets the user spin to any time; `min`/`max` only fir
```tsx live
function example() {
- const at = (h, m) => {
+ const at = (h: number, m: number) => {
const d = new Date();
d.setHours(h, m, 0, 0);
return d;
@@ -412,7 +412,7 @@ The value updates on every increment, digit, or AM/PM toggle — exactly like th
```tsx live
function example() {
- const [v, setV] = useState(() => {
+ const [v, setV] = useState(() => {
const d = new Date();
d.setHours(13, 45, 0, 0);
return d;
@@ -825,7 +825,9 @@ function example() {
v.setHours(8, 30, 0, 0);
return (
- {['primary', 'link', 'info', 'success', 'warning', 'danger'].map(c => (
+ {(
+ ['primary', 'link', 'info', 'success', 'warning', 'danger'] as const
+ ).map(c => (
diff --git a/docs/docs/api/form/field.md b/docs/docs/api/form/field.md
index 4c743e6a3..914030403 100644
--- a/docs/docs/api/form/field.md
+++ b/docs/docs/api/form/field.md
@@ -216,7 +216,7 @@ You can use the `Field` component to create horizontal layouts for static and ed
<>
-
+
diff --git a/docs/docs/api/form/radios.md b/docs/docs/api/form/radios.md
index db607e44b..16a3a237d 100644
--- a/docs/docs/api/form/radios.md
+++ b/docs/docs/api/form/radios.md
@@ -234,7 +234,7 @@ The same `name` propagation works through any wrapper — useful for layouts lik
```tsx live
function RadiosWrappedFormDemo() {
const [submitted, setSubmitted] = React.useState('');
- const RadioCard = ({ value, label }) => (
+ const RadioCard = ({ value, label }: { value: string; label: string }) => (
(
+ const HeartIcon = ({ isActive }: { isActive: boolean }) => (
-
+
diff --git a/docs/docs/api/form/switch.md b/docs/docs/api/form/switch.md
index df7d5e741..22879759a 100644
--- a/docs/docs/api/form/switch.md
+++ b/docs/docs/api/form/switch.md
@@ -263,9 +263,11 @@ function example() {
autoSave: true,
});
- const updateSetting = key => e => {
- setSettings(prev => ({ ...prev, [key]: e.target.checked }));
- };
+ const updateSetting =
+ (key: keyof typeof settings) =>
+ (e: React.ChangeEvent) => {
+ setSettings(prev => ({ ...prev, [key]: e.target.checked }));
+ };
return (
diff --git a/docs/docs/api/form/taginput.md b/docs/docs/api/form/taginput.md
index 51c26c170..37e0cfac8 100644
--- a/docs/docs/api/form/taginput.md
+++ b/docs/docs/api/form/taginput.md
@@ -39,8 +39,10 @@ The component is exported as `Taginput`; a deprecated `TagInput` alias names the
Simple tag input without suggestions.
```tsx live
+import type { TaginputTag } from '@allxsmith/bestax-bulma';
+
function example() {
- const [tags, setTags] = useState(['React', 'TypeScript']);
+ const [tags, setTags] = useState(['React', 'TypeScript']);
return (
@@ -60,8 +62,10 @@ function example() {
Tag input with suggestion dropdown.
```tsx live
+import type { TaginputTag } from '@allxsmith/bestax-bulma';
+
function example() {
- const [tags, setTags] = useState(['React']);
+ const [tags, setTags] = useState(['React']);
const suggestions = [
'React',
'Vue',
@@ -92,8 +96,10 @@ function example() {
Only allow tags from the suggestion list.
```tsx live
+import type { TaginputTag } from '@allxsmith/bestax-bulma';
+
function example() {
- const [tags, setTags] = useState([]);
+ const [tags, setTags] = useState([]);
const categories = [
'Bug',
'Feature',
@@ -202,8 +208,10 @@ Tag inputs in different sizes.
Limit the number of tags allowed.
```tsx live
+import type { TaginputTag } from '@allxsmith/bestax-bulma';
+
function example() {
- const [tags, setTags] = useState(['One', 'Two']);
+ const [tags, setTags] = useState(['One', 'Two']);
return (
@@ -229,8 +237,10 @@ function example() {
Enable duplicate tag values.
```tsx live
+import type { TaginputTag } from '@allxsmith/bestax-bulma';
+
function example() {
- const [tags, setTags] = useState(['Tag']);
+ const [tags, setTags] = useState(['Tag']);
return (
([]);
return (
@@ -405,7 +417,9 @@ Inside a `Control` with no `Field` around it, `Taginput` renders no `Field` of i
Use `value` and `onChange` to manage state externally:
```tsx
-const [tags, setTags] = useState(['React']);
+import type { TaginputTag } from '@allxsmith/bestax-bulma';
+
+const [tags, setTags] = useState(['React']);
;
```
diff --git a/docs/docs/api/helpers/usebulmaclasses.md b/docs/docs/api/helpers/usebulmaclasses.md
index f2f7b16ea..8686d520b 100644
--- a/docs/docs/api/helpers/usebulmaclasses.md
+++ b/docs/docs/api/helpers/usebulmaclasses.md
@@ -192,8 +192,13 @@ The snippets below rebuild simplified components by hand purely to show how `use
`MyColumns` forwards all of its props to `useBulmaClasses` — the `textAlign` and `textTransform` helper props below flow through `props` into the hook (producing `has-text-centered is-uppercase`), while anything the hook doesn't recognize comes back in `rest` and lands on the ``:
```tsx live
+import type { BulmaClassesProps } from '@allxsmith/bestax-bulma';
+
function example() {
- function MyColumns({ children, ...props }) {
+ function MyColumns({
+ children,
+ ...props
+ }: BulmaClassesProps & React.ComponentPropsWithoutRef<'div'>) {
const { bulmaHelperClasses, rest } = useBulmaClasses(props);
return (
@@ -945,6 +950,8 @@ import {
Here is a small custom component that only needs color and spacing helpers:
```tsx live
+import type { BulmaClassesProps } from '@allxsmith/bestax-bulma';
+
function example() {
function PriceTag({
color,
@@ -952,7 +959,7 @@ function example() {
backgroundColorShade,
m,
children,
- }) {
+ }: BulmaClassesProps & { children?: React.ReactNode }) {
const colorClasses = useColorClasses({
color,
backgroundColor,
diff --git a/docs/docs/guides/getting-started/variations.md b/docs/docs/guides/getting-started/variations.md
index 95110193a..c0f17dcb7 100644
--- a/docs/docs/guides/getting-started/variations.md
+++ b/docs/docs/guides/getting-started/variations.md
@@ -28,7 +28,6 @@ import '@allxsmith/bestax-bulma/bestax.css';
**Usage:**
```tsx live
-import React from 'react';
import { Button, Box, Title } from '@allxsmith/bestax-bulma';
import '@allxsmith/bestax-bulma/bestax.css';
@@ -58,7 +57,6 @@ import '@allxsmith/bestax-bulma/versions/bestax-prefixed.css';
**Usage:**
```tsx live
-import React from 'react';
import { ConfigProvider, Button, Box, Title } from '@allxsmith/bestax-bulma';
import '@allxsmith/bestax-bulma/versions/bestax-prefixed.css';
@@ -85,8 +83,9 @@ This renders HTML with prefixed classes:
```html title="HTML markup from example above"
-
Bestax-Prefixed Components
-
+ Bestax-Prefixed Components
+ All components inside this ConfigProvider …
+
Bestax-Prefixed Button
@@ -108,7 +107,6 @@ import '@allxsmith/bestax-bulma/versions/bestax-no-helpers.css';
**Usage:**
```tsx
-import React from 'react';
import { Button, Box, Title } from '@allxsmith/bestax-bulma';
import '@allxsmith/bestax-bulma/versions/bestax-no-helpers.css';
@@ -143,7 +141,6 @@ import '@allxsmith/bestax-bulma/versions/bestax-no-helpers-prefixed.css';
**Usage:**
```tsx
-import React from 'react';
import { ConfigProvider, Button, Box, Title } from '@allxsmith/bestax-bulma';
import '@allxsmith/bestax-bulma/versions/bestax-no-helpers-prefixed.css';
@@ -175,7 +172,6 @@ import '@allxsmith/bestax-bulma/versions/bestax-no-dark-mode.css';
**Usage:**
```tsx
-import React from 'react';
import { Button, Box, Title } from '@allxsmith/bestax-bulma';
import '@allxsmith/bestax-bulma/versions/bestax-no-dark-mode.css';
@@ -233,7 +229,6 @@ For teams that want a custom class prefix matching their brand or organization.
**Usage:**
```tsx
-import React from 'react';
import { ConfigProvider, Button, Box, Title } from '@allxsmith/bestax-bulma';
import './styles/mycompany-bestax.scss';