# All Components Source: /docs/components/overview.md # Components Every component Frontile ships today, grouped by category. Pick one below to jump straight into its docs and live demos. --- # ButtonGroup Source: /docs/components/buttons/button-group.md # ButtonGroup A button group is used to group buttons whose actions are related. ## Import ```js import { ButtonGroup } from 'frontile'; ``` ## Usage ```gts preview import { ButtonGroup } from 'frontile'; ``` ## Using with ToggleButton ```gts preview collapsible import Component from '@glimmer/component'; import { tracked } from '@glimmer/tracking'; import { action } from '@ember/object'; import { fn } from '@ember/helper'; import { ButtonGroup } from 'frontile'; export default class Example extends Component { @tracked isSelected = { first: false, second: false, third: false }; @action onChange(ty: keyof typeof this.isSelected, value: boolean): void { this.isSelected[ty] = value; this.isSelected = { ...this.isSelected }; } } ``` ## ButtonGroup use case A common use case for `ButtonGroup` is to create a split button. ```gts preview import { ButtonGroup } from 'frontile'; import { ChevronDownIcon } from 'site/components/icons'; ``` ## Arguments Arguments passed to `ButtonGroup` are forwarded to every yielded component. Any of them can be overridden on an individual button. ```gts preview import { ButtonGroup } from 'frontile'; ``` ## Accessibility `ButtonGroup` renders `role="group"`, which tells assistive technology that the buttons belong together — but a group with no name is announced as an unlabelled container, so the relationship is stated without being explained. Name it with `aria-label` (or `aria-labelledby` pointing at a visible heading); both pass through to the element via `...attributes`. ```gts preview import { ButtonGroup } from 'frontile'; ``` Grouping does not change how the buttons themselves behave: each stays in the tab order and is reached with `Tab`, not with arrow keys. If you want one selection out of several with arrow-key navigation, that is a radio group rather than a button group — see [RadioGroup](/docs/components/forms/radio-group). Yielded `g.ToggleButton`s each carry their own `aria-pressed`, so a group of them is announced as several independent toggles. That is right for a formatting toolbar where bold and italic can both be on; it is misleading for a set where only one value can be active at a time. ## API ### ButtonGroup **Element:** `HTMLDivElement` **Arguments** | Name | Type | Default | Description | | --- | --- | --- | --- | | `appearance` | `'soft' \| 'custom' \| 'default' \| 'outlined' \| 'minimal' \| 'tonal'` | - | **Deprecated.** Use `variant`. `default` is now `solid`, `outlined` is `outline`, and `minimal` is `plain`. | | `class` | `string` | - | Custom class name, it will override the default ones using Tailwind Merge library. | | `color` | `'neutral' \| 'primary' \| 'secondary' \| 'tertiary' \| 'success' \| 'warning' \| 'danger'` | - | The color of the button | | `intent` | `'default' \| 'primary' \| 'secondary' \| 'tertiary' \| 'success' \| 'warning' \| 'danger'` | - | **Deprecated.** Use `color`. `default` is now `neutral`. | | `size` | `'sm' \| 'md' \| 'lg' \| 'xs' \| 'xl' \| '2xl'` | - | The size of the button | | `variant` | `'solid' \| 'soft' \| 'subtle' \| 'outline' \| 'ghost' \| 'plain' \| 'custom'` | `'solid'` | The button variant. | **Blocks** | Name | Type | Default | Description | | --- | --- | --- | --- | | `default *` | `[{ Button: Button (isInGroup bound); ToggleButton: ToggleButton (isInGroup bound); }]` | - | | --- # Button Source: /docs/components/buttons/button.md # Button The Button component can be used to trigger an action, such as submitting a form, opening a modal, and more. ## Import ```js import { Button } from 'frontile'; ``` ## Usage ```gts preview import { Button } from 'frontile'; ``` ## Button Variants ```gts preview import { Button } from 'frontile'; ``` The `custom` variant is available for the cases where you might want to fully customize the appearance of the button. The default styles are mainly structural. Colors are applied as `color`. ## Button Colors Every color is available in every variant. The label on each row is the `@variant` value; the button labels are the `@color` values. ```gts preview collapsible import { Button } from 'frontile'; import { array } from '@ember/helper'; const colors = [ 'neutral', 'primary', 'secondary', 'tertiary', 'success', 'warning', 'danger' ]; ``` ## Button Sizes ```gts preview import { Button } from 'frontile'; ``` ## With Icons ```gts preview import { Button } from 'frontile'; import { DownloadIcon, ShareIcon, CheckIcon } from 'site/components/icons'; ``` Icons can be placed before or after text. They inherit the button's text color via `currentColor`. ```gts preview import { Button } from 'frontile'; import { DownloadIcon, ShareIcon, CheckIcon } from 'site/components/icons'; ``` Icons passed as plain content keep working exactly as above. The `icon` named block is opt-in sugar: it buys you `@iconPlacement` and, when the button is loading, it is the slot the spinner takes over. ```gts preview import { Button } from 'frontile'; import { ShareIcon } from 'site/components/icons'; ``` ## Label with a Unit A label can carry a smaller trailing unit — a price suffix like `/mo`, a count, or an abbreviation. The label keeps the bold `strong` text role that the size variant already applies; the unit uses the regular-weight `body` role, two steps down the scale. Wrap the pair so the unit sits tight against the label: the button's own `gap` spaces the icon slots, while the wrapper's narrower gap spaces label from unit. ```gts preview import { Button } from 'frontile'; import { StarIcon } from 'site/components/icons'; ``` The unit token pairs with the label token the size variant sets, so it needs to change with `@size`: | `@size` | label (automatic) | unit | wrapper gap | | ------- | ----------------- | --------------- | ----------- | | `xs` | `text-strong-sm` | `text-body-3xs` | `gap-0.5` | | `sm` | `text-strong-md` | `text-body-2xs` | `gap-0.5` | | `md` | `text-strong-lg` | `text-body-xs` | `gap-1` | | `lg` | `text-strong-xl` | `text-body-sm` | `gap-1` | | `xl` | `text-strong-2xl` | `text-body-md` | `gap-1` | | `2xl` | `text-strong-3xl` | `text-body-lg` | `gap-1.5` | ```gts preview import { Button } from 'frontile'; ``` ## Disabled ```gts preview import { Button } from 'frontile'; ``` ## Loading `@isLoading` renders a spinner and disables the button. ```gts preview import { Button } from 'frontile'; ``` Use the `loading` block to swap the label while the action is in flight. ```gts preview import { Button } from 'frontile'; ``` The spinner takes the place of the `icon` block, so a button with an icon keeps its width while loading. ```gts preview import { Button } from 'frontile'; import { ShareIcon } from 'site/components/icons'; ``` `@iconPlacement='end'` moves both the icon and the spinner after the label. ```gts preview import { Button } from 'frontile'; import { ShareIcon } from 'site/components/icons'; ``` ## Renderless Button Sometimes a button element is not ideal for a given case, but the same styles are still desired. Frontile provides the option to disable rendering the `button` element, but instead it yields back an object with the class names it would use. ```gts preview import { Button } from 'frontile'; ``` ## Composition You can compose variant with colors and more to create the button that best fits your needs. ```gts preview import { Button } from 'frontile'; ``` ## Customization You can use TailwindCSS classes to customize even further. ```gts preview import { Button } from 'frontile'; ``` Here is another example using TailwindCSS classes with the `custom` variant. ```gts preview import { Button } from 'frontile'; ``` Note that here we used the HTML attribute `class`, instead of the argument `@class`. Using the class attribute will just append the class names passed in, while the argument `@class` will override and merge TailwindCSS class names. ## Press Interactions The Button component supports press interactions through the `@onPress` callback, which provides cross-platform support for mouse, touch, and keyboard events. ```gts preview import { Button } from 'frontile'; import Component from '@glimmer/component'; import { tracked } from '@glimmer/tracking'; export default class ButtonPressExample extends Component { @tracked pressCount = 0; handlePress = () => { this.pressCount++; }; } ``` ### Press State Buttons automatically track their pressed state and add a `data-pressed` attribute when being pressed, which can be used for styling: ```css button[data-pressed='true'] { transform: scale(0.95); transition: transform 0.1s ease; } ``` ## Accessibility `Button` renders a native `` — stays on screen alongside the spinner, rendering both. If you want the loading-swap behavior, move the icon into `<:icon>`. ### Renderless buttons `@isRenderless` hands back only class names, so every semantic the ` Content here ``` > **Note:** Transitions are registered with an Ember test waiter, so `await settled()` in tests resolves only after the open or close animation has finished. ## API ### Collapsible **Element:** `HTMLDivElement` **Arguments** | Name | Type | Default | Description | | --- | --- | --- | --- | | `isOpen *` | `boolean` | - | If true, the content will be visible | | `initialHeight` | `string` | `0` | The height for the content in it's collapsed state. The unit of the value should be included, eg. '10px'. Any CSS height is accepted (2rem, 50%, calc(1rem + 2px), …); a value the CSS parser rejects is ignored and the content collapses to 0. | **Blocks** | Name | Type | Default | Description | | --- | --- | --- | --- | | `default *` | `[]` | - | | --- # Divider Source: /docs/components/utilities/divider.md # Divider A Divider is designed to delineate and separate content. ## Import ```js import { Divider } from 'frontile'; ``` ## Usage A horizontal divider renders an `
`. ```gts preview import { Divider } from 'frontile'; ``` ## Variants `@variant='sketch'` swaps the flat rule for a hand-drawn one. It stretches to any width without distorting: the artwork is a near-horizontal filled shape, so scaling it horizontally changes only how often it wobbles, never its thickness. ```gts preview import { Divider } from 'frontile'; ``` The line takes its colour from the element's background. By default that is the `divider` token, which is translucent — 15% ink over whatever sits behind it — so one divider reads correctly on a page, a card or a tinted panel without being retuned for each. A utility class recolours it: ```gts preview import { Divider } from 'frontile'; ``` `sketch` is horizontal only. The artwork cannot be squashed into a vertical rule, so `@orientation='vertical'` ignores it and renders the plain line. ## Orientation `@orientation='vertical'` renders a `
` instead, because `
` cannot express a vertical rule. `@variant='sketch'` has no effect on a vertical divider — see Variants. The vertical divider is styled `h-full`, which resolves against its parent — so the parent needs a **definite** height. `items-stretch` alone is not enough: `height: 100%` of an auto-height container computes to zero, and the divider disappears. ```gts preview import { Divider } from 'frontile'; ``` If the row's height has to stay content-driven, override the height on the divider itself instead: ```gts preview import { Divider } from 'frontile'; ``` ## Changing the element `@as` renders a different tag from the one the orientation would pick. This matters when the surrounding markup constrains what is valid — an `
` is not allowed as a direct child of `