Action Bar
A floating contextual toolbar (bulk-selection actions, ...). Purely presentational — no Morphos equivalent.
Installation
npx kosmesis add action-barpnpm dlx kosmesis add action-baryarn dlx kosmesis add action-barbunx kosmesis add action-barThis component builds on other Kosmesis components — install these first (via kosmesis add or this same manual process on their own pages): separator.
Copy and paste the following code into your project.
import { StatelessComponent } from "@praxisjs/core";import { Component } from "@praxisjs/decorators";import type { Children } from "@praxisjs/shared";import { Separator } from "./separator";import { cn } from "@/lib/utils";export interface ActionBarProps { open?: boolean; class?: string; children?: Children;}// Keep mounted and toggle `open` for the enter/exit transition; unmounting skips the exit animation.@Component()export class ActionBar extends StatelessComponent<ActionBarProps> { render() { const { open = true, class: cls, children } = this.props; return ( <div role="toolbar" data-slot="action-bar" data-state={open ? "open" : "closed"} class="pointer-events-none fixed inset-x-0 bottom-6 z-50 flex justify-center px-4" > <div class={cn( "pointer-events-auto flex items-center gap-2 rounded-full border bg-popover px-3 py-2 text-popover-foreground shadow-lg transition-all duration-200", "in-data-[state=closed]:pointer-events-none in-data-[state=closed]:translate-y-2 in-data-[state=closed]:opacity-0", cls, )} > {children} </div> </div> ); }}export interface ActionBarSlotProps { class?: string; children?: Children;}@Component()export class ActionBarText extends StatelessComponent<ActionBarSlotProps> { render() { const { class: cls, children } = this.props; return <span class={cn("px-2 text-sm font-medium whitespace-nowrap", cls)}>{children}</span>; }}@Component()export class ActionBarSeparator extends StatelessComponent<ActionBarSlotProps> { render() { const { class: cls } = this.props; return <Separator orientation="vertical" class={cn("h-5", cls)} />; }}Install the following dependencies:
npm install @praxisjs/csspnpm add @praxisjs/cssyarn add @praxisjs/cssbun add @praxisjs/cssThis component builds on other Kosmesis components — install these first (via kosmesis add or this same manual process on their own pages): separator.
Copy and paste the following code into your project.
import { StatelessComponent } from "@praxisjs/core";import { cx, Stylesheet, Styled, tokenVars } from "@praxisjs/css";import { Component } from "@praxisjs/decorators";import type { Children } from "@praxisjs/shared";import { Separator } from "./separator";import { KosmesisTokens } from "@/lib/kosmesis-theme";const t = tokenVars(KosmesisTokens);class ActionBarStyles extends Stylesheet { $wrapper = this.css({ pointerEvents: "none", position: "fixed", insetInline: "0", bottom: "1.5rem", zIndex: 50, display: "flex", justifyContent: "center", padding: "0 1rem", }); $bar = this.css({ pointerEvents: "auto", display: "flex", alignItems: "center", gap: "0.5rem", borderRadius: "9999px", border: `1px solid ${t.border}`, backgroundColor: t.popover, color: t.popoverForeground, padding: "0.5rem 0.75rem", boxShadow: "0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)", transition: "all 200ms ease", }).on('[data-state="closed"] &', { pointerEvents: "none", transform: "translateY(0.5rem)", opacity: 0 }); $text = this.css({ padding: "0 0.5rem", fontSize: "0.875rem", fontWeight: 500, whiteSpace: "nowrap" }); $separator = this.css({ height: "1.25rem" });}export interface ActionBarProps { open?: boolean; class?: string; children?: Children;}// Keep mounted and toggle `open` for the enter/exit transition; unmounting skips the exit animation.@Component()export class ActionBar extends StatelessComponent<ActionBarProps> { @Styled(ActionBarStyles) $s!: ActionBarStyles; render() { const { open = true, class: cls, children } = this.props; return ( <div role="toolbar" data-slot="action-bar" data-state={open ? "open" : "closed"} class={this.$s.$wrapper}> <div class={cx(this.$s.$bar, cls)}>{children}</div> </div> ); }}export interface ActionBarSlotProps { class?: string; children?: Children;}@Component()export class ActionBarText extends StatelessComponent<ActionBarSlotProps> { @Styled(ActionBarStyles) $s!: ActionBarStyles; render() { const { class: cls, children } = this.props; return <span class={cx(this.$s.$text, cls)}>{children}</span>; }}@Component()export class ActionBarSeparator extends StatelessComponent<ActionBarSlotProps> { @Styled(ActionBarStyles) $s!: ActionBarStyles; render() { const { class: cls } = this.props; return <Separator orientation="vertical" class={cx(this.$s.$separator, cls)} />; }}Examples
About
Purely presentational — no Morphos equivalent. Mount it unconditionally (e.g. alongside a
selectable list) and drive open off your own selection state for the enter/exit transition.
ActionBarSeparator reuses Separator.
Usage
import { ActionBar, ActionBarSeparator, ActionBarText } from "@/components/ui/action-bar";
import { Button } from "@/components/ui/button";
<ActionBar open={selectedIds.length > 0}>
<ActionBarText>{selectedIds.length} selected</ActionBarText>
<ActionBarSeparator />
<Button size="sm" variant="ghost">Archive</Button>
<Button size="sm" variant="destructive">Delete</Button>
</ActionBar>Props
| Prop | Type | Default |
|---|---|---|
open | boolean | true |
class | string | — |
ActionBarText/ActionBarSeparator accept class and (for ActionBarText) children.