diff --git a/packages/controlled-vocabulary/package.json b/packages/controlled-vocabulary/package.json
index 914221726..980ef2f67 100644
--- a/packages/controlled-vocabulary/package.json
+++ b/packages/controlled-vocabulary/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@performant-software/controlled-vocabulary",
-  "version": "2.2.12",
+  "version": "2.2.13",
   "description": "A package of components to allow user to configure dropdown elements. Use with the \"controlled_vocabulary\" gem.",
   "license": "MIT",
   "main": "./dist/index.cjs.js",
@@ -23,8 +23,8 @@
     "underscore": "^1.13.2"
   },
   "peerDependencies": {
-    "@performant-software/semantic-components": "^2.2.12",
-    "@performant-software/shared-components": "^2.2.12",
+    "@performant-software/semantic-components": "^2.2.13",
+    "@performant-software/shared-components": "^2.2.13",
     "react": ">= 16.13.1 < 19.0.0",
     "react-dom": ">= 16.13.1 < 19.0.0"
   },
diff --git a/packages/core-data/package.json b/packages/core-data/package.json
index 8fbb34f2a..429cf38dc 100644
--- a/packages/core-data/package.json
+++ b/packages/core-data/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@performant-software/core-data",
-  "version": "2.2.12",
+  "version": "2.2.13",
   "description": "A package of components used with the Core Data platform.",
   "license": "MIT",
   "main": "./dist/index.cjs.js",
@@ -40,8 +40,8 @@
     "underscore": "^1.13.2"
   },
   "peerDependencies": {
-    "@performant-software/geospatial": "^2.2.12",
-    "@performant-software/shared-components": "^2.2.12",
+    "@performant-software/geospatial": "^2.2.13",
+    "@performant-software/shared-components": "^2.2.13",
     "@peripleo/maplibre": "^0.5.2",
     "@peripleo/peripleo": "^0.5.2",
     "react": ">= 16.13.1 < 19.0.0",
diff --git a/packages/geospatial/package.json b/packages/geospatial/package.json
index 8156aa35f..7ed495eab 100644
--- a/packages/geospatial/package.json
+++ b/packages/geospatial/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@performant-software/geospatial",
-  "version": "2.2.12",
+  "version": "2.2.13",
   "description": "A package of components for all things map-related.",
   "license": "MIT",
   "main": "./dist/index.cjs.js",
diff --git a/packages/semantic-ui/package.json b/packages/semantic-ui/package.json
index 3209e1952..be80dc5a5 100644
--- a/packages/semantic-ui/package.json
+++ b/packages/semantic-ui/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@performant-software/semantic-components",
-  "version": "2.2.12",
+  "version": "2.2.13",
   "description": "A package of shared components based on the Semantic UI Framework.",
   "license": "MIT",
   "main": "./dist/index.cjs.js",
@@ -35,7 +35,7 @@
     "zotero-translation-client": "^5.0.1"
   },
   "peerDependencies": {
-    "@performant-software/shared-components": "^2.2.12",
+    "@performant-software/shared-components": "^2.2.13",
     "@samvera/clover-iiif": "^2.3.2",
     "react": ">= 16.13.1 < 19.0.0",
     "react-dnd": "^11.1.3",
diff --git a/packages/semantic-ui/src/components/DataTable.js b/packages/semantic-ui/src/components/DataTable.js
index 013e790a2..cea9169be 100644
--- a/packages/semantic-ui/src/components/DataTable.js
+++ b/packages/semantic-ui/src/components/DataTable.js
@@ -14,11 +14,9 @@ import _ from 'underscore';
 import i18n from '../i18n/i18n';
 import ColumnResize from './ColumnResize';
 import useColumnSelector, { type Props as ColumnSelectorProps } from './DataTableColumnSelector';
-import useList, { type Props as ListProps } from './List';
+import useList, { type Action, type Props as ListProps } from './List';
 import './DataTable.css';
 
-import type { Action } from './List';
-
 type Props = ListProps & ColumnSelectorProps & {
   /**
    * If <code>true</code>, the rows of the table can be expanded and collapsed.
@@ -302,9 +300,13 @@ class DataTable extends Component<Props, State> {
       return action.render(item, index);
     }
 
+    const { asProps = () => ({}) } = action;
+
     const actionButton = (
       <Button
         aria-label={action.name}
+        as={action.as}
+        {...asProps(item)}
         basic
         compact
         color={action.color}
@@ -348,36 +350,7 @@ class DataTable extends Component<Props, State> {
       return null;
     }
 
-    const actions = this.props.actions
-      .filter((action) => !action.accept || action.accept(item))
-      .map((action) => {
-        let defaults = {};
-
-        if (action.name === 'edit') {
-          defaults = {
-            popup: {
-              title: i18n.t('DataTable.actions.edit.title'),
-              content: i18n.t('DataTable.actions.edit.content')
-            }
-          };
-        } else if (action.name === 'copy') {
-          defaults = {
-            popup: {
-              title: i18n.t('DataTable.actions.copy.title'),
-              content: i18n.t('DataTable.actions.copy.content')
-            }
-          };
-        } else if (action.name === 'delete') {
-          defaults = {
-            popup: {
-              title: i18n.t('DataTable.actions.delete.title'),
-              content: i18n.t('DataTable.actions.delete.content')
-            }
-          };
-        }
-
-        return _.defaults(action, defaults);
-      });
+    const actions = this.props.actions.filter((action) => !action.accept || action.accept(item));
 
     return (
       <Table.Cell
diff --git a/packages/semantic-ui/src/components/Items.js b/packages/semantic-ui/src/components/Items.js
index f65d01fa0..752a74456 100644
--- a/packages/semantic-ui/src/components/Items.js
+++ b/packages/semantic-ui/src/components/Items.js
@@ -8,6 +8,7 @@ import {
   Header,
   Icon,
   Item,
+  Popup,
   Segment
 } from 'semantic-ui-react';
 import _ from 'underscore';
@@ -267,17 +268,7 @@ class ItemsClass extends Component<Props, {}> {
             extra
             textAlign='center'
           >
-            { _.map(actions, (action, actionIndex) => (
-              <Button
-                aria-label={action.name}
-                basic
-                color={action.resolveColor ? action.resolveColor(item) : action.color}
-                icon={action.resolveIcon ? action.resolveIcon(item) : action.icon}
-                key={actionIndex}
-                onClick={action.onClick.bind(this, item)}
-                size={action.size}
-              />
-            ))}
+            { _.map(actions, this.renderCardAction.bind(this, item)) }
             { this.isSelectable() && (
               <Button
                 aria-label='Select'
@@ -309,6 +300,49 @@ class ItemsClass extends Component<Props, {}> {
     return card;
   }
 
+  /**
+   * Renders the action button for the passed item.
+   *
+   * @param action
+   * @param index
+   * @param item
+   *
+   * @returns {JSX.Element}
+   */
+  renderCardAction(item, action, index) {
+    const actionButton = (
+      <Button
+        as={action.as}
+        {...((action.asProps && action.asProps(item)) || {})}
+        aria-label={action.name}
+        basic
+        color={action.resolveColor ? action.resolveColor(item) : action.color}
+        icon={action.resolveIcon ? action.resolveIcon(item) : action.icon}
+        key={index}
+        onClick={action.onClick && action.onClick.bind(this, item)}
+        size={action.size}
+      />
+    );
+
+    // Wrap the button in a popup if the action specifies a popup attribute
+    if (action.popup) {
+      const { content, title } = action.popup;
+
+      return (
+        <Popup
+          content={content}
+          header={title}
+          hideOnScroll
+          mouseEnterDelay={500}
+          position='top right'
+          trigger={actionButton}
+        />
+      );
+    }
+
+    return actionButton;
+  }
+
   /**
    * Renders the empty list.
    *
@@ -405,12 +439,14 @@ class ItemsClass extends Component<Props, {}> {
           )}
           { _.map(this.getActions(item), (action, actionIndex) => (
             <Button
+              as={action.as}
+              {...((action.asProps && action.asProps(item)) || {})}
               basic={action.basic}
               color={action.resolveColor ? action.resolveColor(item) : action.color}
               content={action.resolveName ? action.resolveName(item) : action.label}
               key={actionIndex}
               icon={action.resolveIcon ? action.resolveIcon(item) : action.icon}
-              onClick={action.onClick.bind(this, item)}
+              onClick={action.onClick && action.onClick.bind(this, item)}
               size={action.size}
             />
           ))}
diff --git a/packages/semantic-ui/src/components/List.js b/packages/semantic-ui/src/components/List.js
index 1f38135f9..e4ae02c0b 100644
--- a/packages/semantic-ui/src/components/List.js
+++ b/packages/semantic-ui/src/components/List.js
@@ -20,6 +20,8 @@ import './List.css';
 
 type Action = {
   accept: (item: any) => boolean,
+  as: ComponentType,
+  asProps: () => any,
   color?: string,
   icon?: string,
   name: string,
@@ -525,17 +527,29 @@ const useList = (WrappedComponent: ComponentType<any>) => (
         if (action.name === 'edit') {
           defaults = {
             icon: 'edit outline',
-            onClick: this.onEditButton.bind(this)
+            onClick: this.onEditButton.bind(this),
+            popup: {
+              title: i18n.t('Common.actions.edit.title'),
+              content: i18n.t('Common.actions.edit.content')
+            }
           };
         } else if (action.name === 'copy') {
           defaults = {
             icon: 'copy outline',
-            onClick: this.onCopyButton.bind(this)
+            onClick: this.onCopyButton.bind(this),
+            popup: {
+              title: i18n.t('Common.actions.copy.title'),
+              content: i18n.t('Common.actions.copy.content')
+            }
           };
         } else if (action.name === 'delete') {
           defaults = {
             icon: 'times circle outline',
-            onClick: this.onDeleteButton.bind(this)
+            onClick: this.onDeleteButton.bind(this),
+            popup: {
+              title: i18n.t('Common.actions.delete.title'),
+              content: i18n.t('Common.actions.delete.content')
+            }
           };
         }
 
diff --git a/packages/semantic-ui/src/i18n/en.json b/packages/semantic-ui/src/i18n/en.json
index bb944a165..57e33bdbe 100644
--- a/packages/semantic-ui/src/i18n/en.json
+++ b/packages/semantic-ui/src/i18n/en.json
@@ -42,6 +42,20 @@
     }
   },
   "Common": {
+    "actions": {
+      "copy": {
+        "content": "Creates an editable copy to be saved as a new record",
+        "title": "Copy"
+      },
+      "delete": {
+        "content": "Removes the record, permanently",
+        "title": "Remove"
+      },
+      "edit": {
+        "content": "Opens the modal to edit the record",
+        "title": "Edit"
+      }
+    },
     "buttons": {
       "add": "Add",
       "cancel": "Cancel",
diff --git a/packages/shared/package.json b/packages/shared/package.json
index 4bd71f5b7..b176437ed 100644
--- a/packages/shared/package.json
+++ b/packages/shared/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@performant-software/shared-components",
-  "version": "2.2.12",
+  "version": "2.2.13",
   "description": "A package of shared, framework agnostic, components.",
   "license": "MIT",
   "main": "./dist/index.cjs.js",
diff --git a/packages/storybook/src/semantic-ui/DataTable.stories.js b/packages/storybook/src/semantic-ui/DataTable.stories.js
index 75b226551..f1088bf8e 100644
--- a/packages/storybook/src/semantic-ui/DataTable.stories.js
+++ b/packages/storybook/src/semantic-ui/DataTable.stories.js
@@ -208,6 +208,14 @@ export const CustomActions = useDragDrop(() => (
       name: 'coffee',
       icon: 'coffee',
       onClick: action('coffee-click')
+    }, {
+      as: 'a',
+      asProps: () => ({
+        href: 'https://performantsoftware.com',
+        target: '_blank'
+      }),
+      name: 'link',
+      icon: 'linkify'
     }]}
     columns={columns}
     items={items}
diff --git a/packages/storybook/src/semantic-ui/Items.stories.js b/packages/storybook/src/semantic-ui/Items.stories.js
index aca473536..a723ebdc8 100644
--- a/packages/storybook/src/semantic-ui/Items.stories.js
+++ b/packages/storybook/src/semantic-ui/Items.stories.js
@@ -90,6 +90,19 @@ export const CustomActions = useDragDrop(() => (
       name: 'coffee',
       icon: 'coffee',
       onClick: action('coffee-click')
+    }, {
+      as: 'a',
+      asProps: () => ({
+        href: 'https://performantsoftware.com',
+        target: '_blank'
+      }),
+      basic: true,
+      icon: 'linkify',
+      label: 'Link',
+      popup: {
+        content: 'Testing popup',
+        title: 'POPUP!'
+      }
     }]}
     items={items}
     onCopy={action('copy')}
@@ -197,4 +210,4 @@ export const ButtonSize = useDragDrop(() => (
     renderHeader={(item) => <Header content={item.header} />}
     renderMeta={(item) => item.id}
   />
-));
\ No newline at end of file
+));
diff --git a/packages/user-defined-fields/package.json b/packages/user-defined-fields/package.json
index 1a84a5751..d540db937 100644
--- a/packages/user-defined-fields/package.json
+++ b/packages/user-defined-fields/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@performant-software/user-defined-fields",
-  "version": "2.2.12",
+  "version": "2.2.13",
   "description": "A package of components used for allowing end users to define fields on models. Use with the \"user_defined_fields\" gem.",
   "license": "MIT",
   "main": "./dist/index.cjs.js",
@@ -23,8 +23,8 @@
     "underscore": "^1.13.2"
   },
   "peerDependencies": {
-    "@performant-software/semantic-components": "^2.2.12",
-    "@performant-software/shared-components": "^2.2.12",
+    "@performant-software/semantic-components": "^2.2.13",
+    "@performant-software/shared-components": "^2.2.13",
     "react": ">= 16.13.1 < 19.0.0",
     "react-dom": ">= 16.13.1 < 19.0.0"
   },
diff --git a/packages/visualize/package.json b/packages/visualize/package.json
index 647623881..e1ec9dade 100644
--- a/packages/visualize/package.json
+++ b/packages/visualize/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@performant-software/visualize",
-  "version": "2.2.12",
+  "version": "2.2.13",
   "description": "A package of components used for data visualization",
   "license": "MIT",
   "main": "./dist/index.cjs.js",
diff --git a/react-components.json b/react-components.json
index 0c39ff0d8..044205b5f 100644
--- a/react-components.json
+++ b/react-components.json
@@ -8,5 +8,5 @@
     "packages/user-defined-fields",
     "packages/visualize"
   ],
-  "version": "2.2.12"
+  "version": "2.2.13"
 }