Skip to content

Action Row

The row of buttons and selects attached under a message.

The row of buttons and selects attached under a message. Compose it from the exported registry parts so local content and behaviour stay in the application while the visual contract stays token-driven.

import { ActionRow } from "@/registry/bases/newt/ui/action-row"
import { Button } from "@/registry/bases/newt/ui/button"

export default function ActionRowDemo() {
  return (
    <ActionRow aria-label="Message actions">
      <Button variant="primary">Accept</Button>
      <Button variant="secondary">Decline</Button>
    </ActionRow>
  )
}
<script setup lang="ts">
import { ActionRow } from "~~/registry/bases/newt/ui/action-row"
import { Button } from "~~/registry/bases/newt/ui/button"
</script>

<template>
  <ActionRow aria-label="Message actions">
    <Button variant="primary">Accept</Button>
    <Button variant="secondary">Decline</Button>
  </ActionRow>
</template>

Installation

pnpm dlx newtui@latest add action-row
npx newtui@latest add action-row
yarn dlx newtui@latest add action-row
bunx newtui@latest add action-row

Add the components it builds on

Copy the source into your project

import * as React from "react"

import { cn } from "@/lib/utils"

/*
 * The row of interactive components under a message. Discord fits five per
 * row, so stack rows when a message needs more than that.
 */
const ActionRow = React.forwardRef<
  HTMLDivElement,
  React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
  <div
    ref={ref}
    role="group"
    className={cn("flex flex-wrap items-center gap-2 [&+&]:mt-2", className)}
    {...props}
  />
))
ActionRow.displayName = "ActionRow"

export { ActionRow }
<script setup lang="ts">
import type { HTMLAttributes } from "vue"

import { cn } from "@/lib/utils"

const props = defineProps<{ class?: HTMLAttributes["class"] }>()
</script>

<!--
  The row of interactive components under a message. Discord fits five per
  row, so stack rows when a message needs more than that.
-->
<template>
  <div
    role="group"
    :class="cn('flex flex-wrap items-center gap-2 [&+&]:mt-2', props.class)"
  >
    <slot />
  </div>
</template>
export { default as ActionRow } from "./ActionRow.vue"

Update the import paths

The files import @/lib/utils and sibling components through the aliases in your components.json. Point them at wherever those live in your project.

Usage

import { ActionRow } from "@/components/ui/action-row"

export function Example() {
  return <ActionRow />
}
<script setup lang="ts">
import { ActionRow } from "@/components/ui/action-row"
</script>

<template>
  <ActionRow />
</template>

API reference

ActionRow

PropType
children / default slot?React.ReactNode / Vue slot

Content rendered inside the component.

TypeReact.ReactNode / Vue slot
className / class?string

Additional classes merged with the component defaults.

Typestring

The registry exports ActionRow. Parts without a table accept the native attributes for the element they render; React uses className, while Vue uses class and fallthrough attributes.

Accessibility

Preserve the native semantics of the rendered elements and pass through ARIA attributes when the surrounding context needs a label or description. Any interactive child needs a visible focus indicator, and meaning must not rely on colour alone.

Tokens

Action Row reads its colours, radii and motion from the --newt-* tokens installed with the library. Override a token and every component that reads it follows, including this one — see the token layer.