diff --git a/.vscode/settings.json b/.vscode/settings.json
index e4ea8aee..ac8e05f6 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -5,7 +5,7 @@
"editor.defaultFormatter": "esbenp.prettier-vscode",
"files.eol": "\r\n",
"editor.formatOnSave": true,
- "tailwindCSS.experimental.configFile": "libs/flowbite-angular/styles/flowbite-angular.css",
+ "tailwindCSS.experimental.configFile": "apps/docs/public/css/styles.css",
"tailwindCSS.classAttributes": ["class", "className", "ngClass", "customStyle"],
"tailwindCSS.classFunctions": ["twMerge", "createTheme"],
"typescript.tsdk": "node_modules/typescript/lib",
diff --git a/apps/docs/docs/components/table/_default.component.html b/apps/docs/docs/components/table/_default.component.html
new file mode 100644
index 00000000..d0662fc7
--- /dev/null
+++ b/apps/docs/docs/components/table/_default.component.html
@@ -0,0 +1,54 @@
+
+
+
+ |
+ Product name
+ |
+
+ Qty
+ |
+
+ Price
+ |
+
+
+
+
+ |
+ {{ data.name }}
+ |
+
+ {{ data.qty }}
+ |
+
+ {{ data.price }}
+ |
+
+
+
+
+ |
+ Total
+ |
+ 10 |
+ 30 |
+
+
+
diff --git a/apps/docs/docs/components/table/_default.component.ts b/apps/docs/docs/components/table/_default.component.ts
new file mode 100644
index 00000000..87261cfe
--- /dev/null
+++ b/apps/docs/docs/components/table/_default.component.ts
@@ -0,0 +1,18 @@
+import { Table, TableBody, TableFoot, TableHead } from 'flowbite-angular/table';
+
+import { Component } from '@angular/core';
+
+@Component({
+ imports: [Table, TableBody, TableFoot, TableHead],
+ templateUrl: './_default.component.html',
+ host: {
+ class: 'flex flex-wrap flex-row gap-3 p-6',
+ },
+})
+export class FlowbiteDefaultComponent {
+ readonly data = Array.from({ length: 5 }, (_, i) => i++).map((x) => ({
+ name: `Product ${x}`,
+ qty: x,
+ price: x * x,
+ }));
+}
diff --git a/apps/docs/docs/components/table/index.md b/apps/docs/docs/components/table/index.md
new file mode 100644
index 00000000..8fbead47
--- /dev/null
+++ b/apps/docs/docs/components/table/index.md
@@ -0,0 +1,18 @@
+---
+keyword: TablePage
+---
+
+## Default Table
+
+{{ NgDocActions.demo('flowbiteDefaultComponent', {container: false}) }}
+
+```angular-html file="./_default.component.html" group="default" name="html"
+
+```
+
+```angular-ts file="./_default.component.ts" group="default" name="typescript"
+
+```
+
+{% import "../../shared/theme-macro.md" as themeMacro %}
+{{ themeMacro.display(NgDocPage.data.themes) }}
diff --git a/apps/docs/docs/components/table/ng-doc.page.ts b/apps/docs/docs/components/table/ng-doc.page.ts
new file mode 100644
index 00000000..44feb99e
--- /dev/null
+++ b/apps/docs/docs/components/table/ng-doc.page.ts
@@ -0,0 +1,35 @@
+import type { DocThemes } from '../../doc-theme.model';
+import { toIndentedJson } from '../../doc-theme.model';
+import ComponentCategory from '../ng-doc.category';
+import { FlowbiteDefaultComponent } from './_default.component';
+
+import {
+ flowbiteTableBodyTheme,
+ flowbiteTableFootTheme,
+ flowbiteTableHeadTheme,
+ flowbiteTableTheme,
+} from 'flowbite-angular/table';
+
+import type { NgDocPage } from '@ng-doc/core';
+
+/**
+ *
+ */
+const Table: NgDocPage = {
+ title: 'Table',
+ mdFile: './index.md',
+ category: ComponentCategory,
+ demos: {
+ flowbiteDefaultComponent: FlowbiteDefaultComponent,
+ },
+ data: {
+ themes: [
+ { title: 'Table', content: toIndentedJson(flowbiteTableTheme) },
+ { title: 'Table Head', content: toIndentedJson(flowbiteTableHeadTheme) },
+ { title: 'Table Body', content: toIndentedJson(flowbiteTableBodyTheme) },
+ { title: 'Table Foot', content: toIndentedJson(flowbiteTableFootTheme) },
+ ] satisfies DocThemes,
+ },
+};
+
+export default Table;
diff --git a/apps/docs/docs/ng-doc.api.ts b/apps/docs/docs/ng-doc.api.ts
index d07abf0e..312d1223 100644
--- a/apps/docs/docs/ng-doc.api.ts
+++ b/apps/docs/docs/ng-doc.api.ts
@@ -31,6 +31,7 @@ const api: NgDocApi = {
'libs/flowbite-angular/sidebar/src/index.ts',
'libs/flowbite-angular/tab/src/index.ts',
'libs/flowbite-angular/theme-toggle/src/index.ts',
+ 'libs/flowbite-angular/table/src/index.ts',
'libs/flowbite-angular/tooltip/src/index.ts',
],
},
diff --git a/apps/storybook/src/table.component.stories.ts b/apps/storybook/src/table.component.stories.ts
new file mode 100644
index 00000000..6b8f20fb
--- /dev/null
+++ b/apps/storybook/src/table.component.stories.ts
@@ -0,0 +1,125 @@
+import {
+ defaultFlowbiteTableConfig,
+ Table,
+ TableBody,
+ TableFoot,
+ TableHead,
+} from 'flowbite-angular/table';
+
+import type { Meta, StoryObj } from '@storybook/angular';
+import { argsToTemplate, moduleMetadata } from '@storybook/angular';
+
+type StoryType = Table;
+
+export default {
+ title: 'Component/Table',
+ component: Table,
+ decorators: [
+ moduleMetadata({
+ imports: [TableHead, TableBody, TableFoot],
+ }),
+ ],
+ argTypes: {
+ color: {
+ control: 'select',
+ type: 'string',
+ options: ['default', 'info', 'failure', 'success', 'warning', 'primary'],
+ table: {
+ category: 'Input',
+ defaultValue: {
+ summary: JSON.stringify(defaultFlowbiteTableConfig.color),
+ },
+ },
+ },
+ striped: {
+ control: 'boolean',
+ type: 'boolean',
+ table: {
+ category: 'Input',
+ defaultValue: {
+ summary: JSON.stringify(defaultFlowbiteTableConfig.striped),
+ },
+ },
+ },
+ data: {
+ control: 'object',
+ type: 'symbol',
+ table: {
+ category: 'Input',
+ defaultValue: {
+ summary: JSON.stringify([]),
+ },
+ },
+ },
+ customTheme: {
+ control: 'object',
+ type: 'symbol',
+ table: {
+ category: 'Input',
+ defaultValue: {
+ summary: JSON.stringify(defaultFlowbiteTableConfig.customTheme),
+ },
+ },
+ },
+ },
+} as Meta;
+
+export const Default: StoryObj = {
+ name: 'Default',
+ args: {
+ color: defaultFlowbiteTableConfig.color,
+ striped: defaultFlowbiteTableConfig.striped,
+ data: Array.from({ length: 5 }, (_, i) => i++).map((x) => ({
+ name: `Product ${x}`,
+ qty: x,
+ price: x * x,
+ })),
+ customTheme: defaultFlowbiteTableConfig.customTheme,
+ },
+ render: (args) => ({
+ props: args,
+ template: `
+
+
+
+ |
+ Product name
+ |
+
+ Qty
+ |
+
+ Price
+ |
+
+
+
+
+ |
+ {{ data.name }}
+ |
+
+ {{ data.qty }}
+ |
+
+ {{ data.price }}
+ |
+
+
+
+
+ |
+ Total
+ |
+
+ 10
+ |
+
+ 30
+ |
+
+
+
+ `,
+ }),
+};
diff --git a/libs/flowbite-angular/table/README.md b/libs/flowbite-angular/table/README.md
new file mode 100644
index 00000000..b6d036db
--- /dev/null
+++ b/libs/flowbite-angular/table/README.md
@@ -0,0 +1,4 @@
+# flowbite-angular/table
+
+Secondary entry point of `flowbite-angular`. It can be used by importing from
+`flowbite-angular/table`.
diff --git a/libs/flowbite-angular/table/ng-package.json b/libs/flowbite-angular/table/ng-package.json
new file mode 100644
index 00000000..c781f0df
--- /dev/null
+++ b/libs/flowbite-angular/table/ng-package.json
@@ -0,0 +1,5 @@
+{
+ "lib": {
+ "entryFile": "src/index.ts"
+ }
+}
diff --git a/libs/flowbite-angular/table/src/config/table-body-config.ts b/libs/flowbite-angular/table/src/config/table-body-config.ts
new file mode 100644
index 00000000..a43c3260
--- /dev/null
+++ b/libs/flowbite-angular/table/src/config/table-body-config.ts
@@ -0,0 +1,49 @@
+import { flowbiteTableBodyTheme, type FlowbiteTableBodyTheme } from '../table-body/theme';
+
+import type { DeepPartial } from 'flowbite-angular';
+
+import type { Provider } from '@angular/core';
+import { inject, InjectionToken } from '@angular/core';
+
+export interface FlowbiteTableBodyConfig {
+ /**
+ * The default theme of table-body
+ */
+ baseTheme: FlowbiteTableBodyTheme;
+
+ /**
+ * The custom theme of table-body
+ */
+ customTheme: DeepPartial;
+}
+
+export const defaultFlowbiteTableBodyConfig: FlowbiteTableBodyConfig = {
+ baseTheme: flowbiteTableBodyTheme,
+ customTheme: {},
+};
+
+export const FlowbiteTableBodyConfigToken = new InjectionToken(
+ 'FlowbiteTableBodyConfigToken'
+);
+
+/**
+ * Provide the default TableBody configuration
+ * @param config The TableBody configuration
+ * @returns The provider
+ */
+export const provideFlowbiteTableBodyConfig = (
+ config: Partial
+): Provider[] => [
+ {
+ provide: FlowbiteTableBodyConfigToken,
+ useValue: { ...defaultFlowbiteTableBodyConfig, ...config },
+ },
+];
+
+/**
+ * Inject the TableBody configuration
+ * @see {@link defaultFlowbiteTableBodyConfig}
+ * @returns The configuration
+ */
+export const injectFlowbiteTableBodyConfig = (): FlowbiteTableBodyConfig =>
+ inject(FlowbiteTableBodyConfigToken, { optional: true }) ?? defaultFlowbiteTableBodyConfig;
diff --git a/libs/flowbite-angular/table/src/config/table-config.ts b/libs/flowbite-angular/table/src/config/table-config.ts
new file mode 100644
index 00000000..5ad1274d
--- /dev/null
+++ b/libs/flowbite-angular/table/src/config/table-config.ts
@@ -0,0 +1,57 @@
+import type { FlowbiteTableColors } from '../table/theme';
+import { flowbiteTableTheme, type FlowbiteTableTheme } from '../table/theme';
+
+import type { DeepPartial } from 'flowbite-angular';
+
+import type { Provider } from '@angular/core';
+import { inject, InjectionToken } from '@angular/core';
+
+export interface FlowbiteTableConfig {
+ /**
+ * The default theme of table
+ */
+ baseTheme: FlowbiteTableTheme;
+ /**
+ * The default color of table.
+ */
+ color: keyof FlowbiteTableColors;
+ /**
+ * Whether the table is striped.
+ */
+ striped: boolean;
+ /**
+ * The custom theme of table
+ */
+ customTheme: DeepPartial;
+}
+
+export const defaultFlowbiteTableConfig: FlowbiteTableConfig = {
+ baseTheme: flowbiteTableTheme,
+ color: 'default',
+ striped: false,
+ customTheme: {},
+};
+
+export const FlowbiteTableConfigToken = new InjectionToken(
+ 'FlowbiteTableConfigToken'
+);
+
+/**
+ * Provide the default Table configuration
+ * @param config The Table configuration
+ * @returns The provider
+ */
+export const provideFlowbiteTableConfig = (config: Partial): Provider[] => [
+ {
+ provide: FlowbiteTableConfigToken,
+ useValue: { ...defaultFlowbiteTableConfig, ...config },
+ },
+];
+
+/**
+ * Inject the Table configuration
+ * @see {@link defaultFlowbiteTableConfig}
+ * @returns The configuration
+ */
+export const injectFlowbiteTableConfig = (): FlowbiteTableConfig =>
+ inject(FlowbiteTableConfigToken, { optional: true }) ?? defaultFlowbiteTableConfig;
diff --git a/libs/flowbite-angular/table/src/config/table-foot-config.ts b/libs/flowbite-angular/table/src/config/table-foot-config.ts
new file mode 100644
index 00000000..49f314dc
--- /dev/null
+++ b/libs/flowbite-angular/table/src/config/table-foot-config.ts
@@ -0,0 +1,49 @@
+import { flowbiteTableFootTheme, type FlowbiteTableFootTheme } from '../table-foot/theme';
+
+import type { DeepPartial } from 'flowbite-angular';
+
+import type { Provider } from '@angular/core';
+import { inject, InjectionToken } from '@angular/core';
+
+export interface FlowbiteTableFootConfig {
+ /**
+ * The default theme of table-foot
+ */
+ baseTheme: FlowbiteTableFootTheme;
+
+ /**
+ * The custom theme of table-foot
+ */
+ customTheme: DeepPartial;
+}
+
+export const defaultFlowbiteTableFootConfig: FlowbiteTableFootConfig = {
+ baseTheme: flowbiteTableFootTheme,
+ customTheme: {},
+};
+
+export const FlowbiteTableFootConfigToken = new InjectionToken(
+ 'FlowbiteTableFootConfigToken'
+);
+
+/**
+ * Provide the default TableFoot configuration
+ * @param config The TableFoot configuration
+ * @returns The provider
+ */
+export const provideFlowbiteTableFootConfig = (
+ config: Partial
+): Provider[] => [
+ {
+ provide: FlowbiteTableFootConfigToken,
+ useValue: { ...defaultFlowbiteTableFootConfig, ...config },
+ },
+];
+
+/**
+ * Inject the TableFoot configuration
+ * @see {@link defaultFlowbiteTableFootConfig}
+ * @returns The configuration
+ */
+export const injectFlowbiteTableFootConfig = (): FlowbiteTableFootConfig =>
+ inject(FlowbiteTableFootConfigToken, { optional: true }) ?? defaultFlowbiteTableFootConfig;
diff --git a/libs/flowbite-angular/table/src/config/table-head-config.ts b/libs/flowbite-angular/table/src/config/table-head-config.ts
new file mode 100644
index 00000000..2866fb4f
--- /dev/null
+++ b/libs/flowbite-angular/table/src/config/table-head-config.ts
@@ -0,0 +1,49 @@
+import { flowbiteTableHeadTheme, type FlowbiteTableHeadTheme } from '../table-head/theme';
+
+import type { DeepPartial } from 'flowbite-angular';
+
+import type { Provider } from '@angular/core';
+import { inject, InjectionToken } from '@angular/core';
+
+export interface FlowbiteTableHeadConfig {
+ /**
+ * The default theme of table-head
+ */
+ baseTheme: FlowbiteTableHeadTheme;
+
+ /**
+ * The custom theme of table-head
+ */
+ customTheme: DeepPartial;
+}
+
+export const defaultFlowbiteTableHeadConfig: FlowbiteTableHeadConfig = {
+ baseTheme: flowbiteTableHeadTheme,
+ customTheme: {},
+};
+
+export const FlowbiteTableHeadConfigToken = new InjectionToken(
+ 'FlowbiteTableHeadConfigToken'
+);
+
+/**
+ * Provide the default TableHead configuration
+ * @param config The TableHead configuration
+ * @returns The provider
+ */
+export const provideFlowbiteTableHeadConfig = (
+ config: Partial
+): Provider[] => [
+ {
+ provide: FlowbiteTableHeadConfigToken,
+ useValue: { ...defaultFlowbiteTableHeadConfig, ...config },
+ },
+];
+
+/**
+ * Inject the TableHead configuration
+ * @see {@link defaultFlowbiteTableHeadConfig}
+ * @returns The configuration
+ */
+export const injectFlowbiteTableHeadConfig = (): FlowbiteTableHeadConfig =>
+ inject(FlowbiteTableHeadConfigToken, { optional: true }) ?? defaultFlowbiteTableHeadConfig;
diff --git a/libs/flowbite-angular/table/src/index.ts b/libs/flowbite-angular/table/src/index.ts
new file mode 100644
index 00000000..a055263f
--- /dev/null
+++ b/libs/flowbite-angular/table/src/index.ts
@@ -0,0 +1,27 @@
+/* Table */
+export * from './table/table.component';
+export * from './table/table-state';
+export * from './table/theme';
+/* Config */
+export * from './config/table-config';
+
+/* TableHead */
+export * from './table-head/table-head.directive';
+export * from './table-head/table-head-state';
+export * from './table-head/theme';
+/* Config */
+export * from './config/table-head-config';
+
+/* TableBody */
+export * from './table-body/table-body.directive';
+export * from './table-body/table-body-state';
+export * from './table-body/theme';
+/* Config */
+export * from './config/table-body-config';
+
+/* TableFoot */
+export * from './table-foot/table-foot.directive';
+export * from './table-foot/table-foot-state';
+export * from './table-foot/theme';
+/* Config */
+export * from './config/table-foot-config';
diff --git a/libs/flowbite-angular/table/src/table-body/table-body-state.ts b/libs/flowbite-angular/table/src/table-body/table-body-state.ts
new file mode 100644
index 00000000..82bd1c4d
--- /dev/null
+++ b/libs/flowbite-angular/table/src/table-body/table-body-state.ts
@@ -0,0 +1,13 @@
+import type { TableBody } from './table-body.directive';
+
+import {
+ createState,
+ createStateInjector,
+ createStateProvider,
+ createStateToken,
+} from 'ng-primitives/state';
+
+export const FlowbiteTableBodyStateToken = createStateToken('Flowbite TableBody');
+export const provideFlowbiteTableBodyState = createStateProvider(FlowbiteTableBodyStateToken);
+export const injectFlowbiteTableBodyState = createStateInjector(FlowbiteTableBodyStateToken);
+export const flowbiteTableBodyState = createState(FlowbiteTableBodyStateToken);
diff --git a/libs/flowbite-angular/table/src/table-body/table-body.directive.ts b/libs/flowbite-angular/table/src/table-body/table-body.directive.ts
new file mode 100644
index 00000000..0bda2caa
--- /dev/null
+++ b/libs/flowbite-angular/table/src/table-body/table-body.directive.ts
@@ -0,0 +1,49 @@
+import { injectFlowbiteTableBodyConfig } from '../config/table-body-config';
+import { injectFlowbiteTableState } from '../table/table-state';
+import { flowbiteTableBodyState, provideFlowbiteTableBodyState } from './table-body-state';
+
+import { colorToTheme, mergeDeep } from 'flowbite-angular';
+
+import { computed, Directive, input } from '@angular/core';
+import { twMerge } from 'tailwind-merge';
+
+@Directive({
+ standalone: true,
+ selector: `
+ tr[flowbiteTableBody]
+ `,
+ exportAs: 'flowbiteTableBody',
+ hostDirectives: [],
+ providers: [provideFlowbiteTableBodyState()],
+ host: {
+ '[class]': `theme().host.root`,
+ '[attr.data-striped]': 'tableState().striped() || undefined',
+ },
+})
+export class TableBody {
+ readonly config = injectFlowbiteTableBodyConfig();
+ readonly tableState = injectFlowbiteTableState();
+
+ /**
+ * @see {@link injectFlowbiteTableBodyConfig}
+ */
+ readonly customTheme = input(this.config.customTheme);
+
+ readonly theme = computed(() => {
+ const mergedTheme = mergeDeep(this.config.baseTheme, this.state.customTheme());
+
+ return {
+ host: {
+ root: twMerge(
+ mergedTheme.host.base,
+ colorToTheme(mergedTheme.host.color, this.tableState().color())
+ ),
+ },
+ };
+ });
+
+ /**
+ * @internal
+ */
+ readonly state = flowbiteTableBodyState(this);
+}
diff --git a/libs/flowbite-angular/table/src/table-body/theme.ts b/libs/flowbite-angular/table/src/table-body/theme.ts
new file mode 100644
index 00000000..7d4d0409
--- /dev/null
+++ b/libs/flowbite-angular/table/src/table-body/theme.ts
@@ -0,0 +1,44 @@
+import type { FlowbiteTableColors } from '../table/theme';
+
+import { createTheme } from 'flowbite-angular';
+
+export interface FlowbiteTableBodyTheme {
+ host: FlowbiteTableBodyHostTheme;
+}
+
+export interface FlowbiteTableBodyHostTheme {
+ base: string;
+ color: FlowbiteTableColors;
+}
+
+export const flowbiteTableBodyTheme: FlowbiteTableBodyTheme = createTheme({
+ host: {
+ base: 'border-b',
+ color: {
+ default: {
+ light: 'border-gray-200 data-striped:odd:bg-white data-striped:even:bg-gray-50',
+ dark: 'dark:border-gray-700 data-striped:odd:dark:bg-gray-900 data-striped:even:dark:bg-gray-800',
+ },
+ info: {
+ light: 'border-blue-200 data-striped:odd:bg-white data-striped:even:bg-blue-50',
+ dark: 'dark:border-blue-900 data-striped:odd:dark:bg-blue-950 data-striped:even:dark:bg-blue-900',
+ },
+ failure: {
+ light: 'border-red-200 data-striped:odd:bg-white data-striped:even:bg-red-50',
+ dark: 'dark:border-red-900 data-striped:odd:dark:bg-red-950 data-striped:even:dark:bg-red-900',
+ },
+ success: {
+ light: 'border-green-200 data-striped:odd:bg-white data-striped:even:bg-green-50',
+ dark: 'dark:border-green-900 data-striped:odd:dark:bg-green-950 data-striped:even:dark:bg-green-900',
+ },
+ warning: {
+ light: 'border-yellow-200 data-striped:odd:bg-white data-striped:even:bg-yellow-50',
+ dark: 'dark:border-yellow-900 data-striped:odd:dark:bg-yellow-950 data-striped:even:dark:bg-yellow-900',
+ },
+ primary: {
+ light: 'border-primary-200 data-striped:even:bg-primary-50 data-striped:odd:bg-white',
+ dark: 'dark:border-primary-900 data-striped:odd:dark:bg-primary-950 data-striped:even:dark:bg-primary-900',
+ },
+ },
+ },
+});
diff --git a/libs/flowbite-angular/table/src/table-foot/table-foot-state.ts b/libs/flowbite-angular/table/src/table-foot/table-foot-state.ts
new file mode 100644
index 00000000..1b4ce09e
--- /dev/null
+++ b/libs/flowbite-angular/table/src/table-foot/table-foot-state.ts
@@ -0,0 +1,13 @@
+import type { TableFoot } from './table-foot.directive';
+
+import {
+ createState,
+ createStateInjector,
+ createStateProvider,
+ createStateToken,
+} from 'ng-primitives/state';
+
+export const FlowbiteTableFootStateToken = createStateToken('Flowbite TableFoot');
+export const provideFlowbiteTableFootState = createStateProvider(FlowbiteTableFootStateToken);
+export const injectFlowbiteTableFootState = createStateInjector(FlowbiteTableFootStateToken);
+export const flowbiteTableFootState = createState(FlowbiteTableFootStateToken);
diff --git a/libs/flowbite-angular/table/src/table-foot/table-foot.directive.ts b/libs/flowbite-angular/table/src/table-foot/table-foot.directive.ts
new file mode 100644
index 00000000..006375e2
--- /dev/null
+++ b/libs/flowbite-angular/table/src/table-foot/table-foot.directive.ts
@@ -0,0 +1,46 @@
+import { injectFlowbiteTableFootConfig } from '../config/table-foot-config';
+import { injectFlowbiteTableState } from '../table/table-state';
+import { flowbiteTableFootState, provideFlowbiteTableFootState } from './table-foot-state';
+
+import { colorToTheme, mergeDeep } from 'flowbite-angular';
+
+import { computed, Directive, input } from '@angular/core';
+import { twMerge } from 'tailwind-merge';
+
+@Directive({
+ standalone: true,
+ selector: `
+ tr[flowbiteTableFoot]
+ `,
+ exportAs: 'flowbiteTableFoot',
+ hostDirectives: [],
+ providers: [provideFlowbiteTableFootState()],
+ host: { '[class]': `theme().host.root` },
+})
+export class TableFoot {
+ readonly config = injectFlowbiteTableFootConfig();
+ readonly tableState = injectFlowbiteTableState();
+
+ /**
+ * @see {@link injectFlowbiteTableFootConfig}
+ */
+ readonly customTheme = input(this.config.customTheme);
+
+ readonly theme = computed(() => {
+ const mergedTheme = mergeDeep(this.config.baseTheme, this.state.customTheme());
+
+ return {
+ host: {
+ root: twMerge(
+ mergedTheme.host.base,
+ colorToTheme(mergedTheme.host.color, this.tableState().color())
+ ),
+ },
+ };
+ });
+
+ /**
+ * @internal
+ */
+ readonly state = flowbiteTableFootState(this);
+}
diff --git a/libs/flowbite-angular/table/src/table-foot/theme.ts b/libs/flowbite-angular/table/src/table-foot/theme.ts
new file mode 100644
index 00000000..a254aea4
--- /dev/null
+++ b/libs/flowbite-angular/table/src/table-foot/theme.ts
@@ -0,0 +1,44 @@
+import type { FlowbiteTableColors } from '../table/theme';
+
+import { createTheme } from 'flowbite-angular';
+
+export interface FlowbiteTableFootTheme {
+ host: FlowbiteTableFootHostTheme;
+}
+
+export interface FlowbiteTableFootHostTheme {
+ base: string;
+ color: FlowbiteTableColors;
+}
+
+export const flowbiteTableFootTheme: FlowbiteTableFootTheme = createTheme({
+ host: {
+ base: 'font-semibold',
+ color: {
+ default: {
+ light: 'text-gray-900',
+ dark: 'dark:text-white',
+ },
+ info: {
+ light: 'text-gray-900',
+ dark: 'dark:text-white',
+ },
+ failure: {
+ light: 'text-gray-900',
+ dark: 'dark:text-white',
+ },
+ success: {
+ light: 'text-gray-900',
+ dark: 'dark:text-white',
+ },
+ warning: {
+ light: 'text-gray-900',
+ dark: 'dark:text-white',
+ },
+ primary: {
+ light: 'text-gray-900',
+ dark: 'dark:text-white',
+ },
+ },
+ },
+});
diff --git a/libs/flowbite-angular/table/src/table-head/table-head-state.ts b/libs/flowbite-angular/table/src/table-head/table-head-state.ts
new file mode 100644
index 00000000..a36f9287
--- /dev/null
+++ b/libs/flowbite-angular/table/src/table-head/table-head-state.ts
@@ -0,0 +1,13 @@
+import type { TableHead } from './table-head.directive';
+
+import {
+ createState,
+ createStateInjector,
+ createStateProvider,
+ createStateToken,
+} from 'ng-primitives/state';
+
+export const FlowbiteTableHeadStateToken = createStateToken('Flowbite TableHead');
+export const provideFlowbiteTableHeadState = createStateProvider(FlowbiteTableHeadStateToken);
+export const injectFlowbiteTableHeadState = createStateInjector(FlowbiteTableHeadStateToken);
+export const flowbiteTableHeadState = createState(FlowbiteTableHeadStateToken);
diff --git a/libs/flowbite-angular/table/src/table-head/table-head.directive.ts b/libs/flowbite-angular/table/src/table-head/table-head.directive.ts
new file mode 100644
index 00000000..308890b7
--- /dev/null
+++ b/libs/flowbite-angular/table/src/table-head/table-head.directive.ts
@@ -0,0 +1,46 @@
+import { injectFlowbiteTableHeadConfig } from '../config/table-head-config';
+import { injectFlowbiteTableState } from '../table/table-state';
+import { flowbiteTableHeadState, provideFlowbiteTableHeadState } from './table-head-state';
+
+import { colorToTheme, mergeDeep } from 'flowbite-angular';
+
+import { computed, Directive, input } from '@angular/core';
+import { twMerge } from 'tailwind-merge';
+
+@Directive({
+ standalone: true,
+ selector: `
+ tr[flowbiteTableHead]
+ `,
+ exportAs: 'flowbiteTableHead',
+ hostDirectives: [],
+ providers: [provideFlowbiteTableHeadState()],
+ host: { '[class]': `theme().host.root` },
+})
+export class TableHead {
+ readonly config = injectFlowbiteTableHeadConfig();
+ readonly tableState = injectFlowbiteTableState();
+
+ /**
+ * @see {@link injectFlowbiteTableHeadConfig}
+ */
+ readonly customTheme = input(this.config.customTheme);
+
+ readonly theme = computed(() => {
+ const mergedTheme = mergeDeep(this.config.baseTheme, this.state.customTheme());
+
+ return {
+ host: {
+ root: twMerge(
+ mergedTheme.host.base,
+ colorToTheme(mergedTheme.host.color, this.tableState().color())
+ ),
+ },
+ };
+ });
+
+ /**
+ * @internal
+ */
+ readonly state = flowbiteTableHeadState(this);
+}
diff --git a/libs/flowbite-angular/table/src/table-head/theme.ts b/libs/flowbite-angular/table/src/table-head/theme.ts
new file mode 100644
index 00000000..2a6890b9
--- /dev/null
+++ b/libs/flowbite-angular/table/src/table-head/theme.ts
@@ -0,0 +1,44 @@
+import type { FlowbiteTableColors } from '../table/theme';
+
+import { createTheme } from 'flowbite-angular';
+
+export interface FlowbiteTableHeadTheme {
+ host: FlowbiteTableHeadHostTheme;
+}
+
+export interface FlowbiteTableHeadHostTheme {
+ base: string;
+ color: FlowbiteTableColors;
+}
+
+export const flowbiteTableHeadTheme: FlowbiteTableHeadTheme = createTheme({
+ host: {
+ base: 'text-xs uppercase',
+ color: {
+ default: {
+ light: 'bg-gray-50 text-gray-700',
+ dark: 'dark:bg-gray-700 dark:text-gray-400',
+ },
+ info: {
+ light: 'bg-blue-50 text-blue-700',
+ dark: 'dark:bg-blue-700 dark:text-blue-400',
+ },
+ failure: {
+ light: 'bg-red-50 text-red-700',
+ dark: 'dark:bg-red-700 dark:text-red-300',
+ },
+ success: {
+ light: 'bg-green-50 text-green-700',
+ dark: 'dark:bg-green-700 dark:text-green-400',
+ },
+ warning: {
+ light: 'bg-yellow-50 text-yellow-700',
+ dark: 'dark:bg-yellow-700 dark:text-yellow-400',
+ },
+ primary: {
+ light: 'bg-primary-50 text-primary-700',
+ dark: 'dark:bg-primary-700 dark:text-primary-300',
+ },
+ },
+ },
+});
diff --git a/libs/flowbite-angular/table/src/table/table-state.ts b/libs/flowbite-angular/table/src/table/table-state.ts
new file mode 100644
index 00000000..e93f6e56
--- /dev/null
+++ b/libs/flowbite-angular/table/src/table/table-state.ts
@@ -0,0 +1,13 @@
+import type { Table } from './table.component';
+
+import {
+ createState,
+ createStateInjector,
+ createStateProvider,
+ createStateToken,
+} from 'ng-primitives/state';
+
+export const FlowbiteTableStateToken = createStateToken('Flowbite Table');
+export const provideFlowbiteTableState = createStateProvider(FlowbiteTableStateToken);
+export const injectFlowbiteTableState = createStateInjector(FlowbiteTableStateToken);
+export const flowbiteTableState = createState(FlowbiteTableStateToken);
diff --git a/libs/flowbite-angular/table/src/table/table.component.ts b/libs/flowbite-angular/table/src/table/table.component.ts
new file mode 100644
index 00000000..2c213058
--- /dev/null
+++ b/libs/flowbite-angular/table/src/table/table.component.ts
@@ -0,0 +1,84 @@
+import { injectFlowbiteTableConfig } from '../config/table-config';
+import { flowbiteTableState, provideFlowbiteTableState } from './table-state';
+
+import { colorToTheme, mergeDeep } from 'flowbite-angular';
+
+import { NgTemplateOutlet } from '@angular/common';
+import type { TemplateRef } from '@angular/core';
+import {
+ ChangeDetectionStrategy,
+ Component,
+ computed,
+ input,
+ ViewEncapsulation,
+} from '@angular/core';
+import { twMerge } from 'tailwind-merge';
+
+@Component({
+ standalone: true,
+ selector: `
+ table[flowbiteTable]
+ `,
+ exportAs: 'flowbiteTable',
+ hostDirectives: [],
+ imports: [NgTemplateOutlet],
+ providers: [provideFlowbiteTableState()],
+ host: { '[class]': `theme().host.root` },
+ template: `
+
+
+
+
+ @for (record of state.data(); track $index) {
+
+ }
+
+
+
+
+ `,
+ encapsulation: ViewEncapsulation.None,
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class Table {
+ readonly config = injectFlowbiteTableConfig();
+
+ readonly tableHead = input>();
+ readonly tableBody = input>();
+ readonly data = input();
+ readonly tableFoot = input>();
+
+ /**
+ * @see {@link injectFlowbiteTableConfig}
+ */
+ readonly color = input(this.config.color);
+ /**
+ * @see {@link injectFlowbiteTableConfig}
+ */
+ readonly striped = input(this.config.striped);
+
+ /**
+ * @see {@link injectFlowbiteTableConfig}
+ */
+ readonly customTheme = input(this.config.customTheme);
+
+ readonly theme = computed(() => {
+ const mergedTheme = mergeDeep(this.config.baseTheme, this.state.customTheme());
+
+ return {
+ host: {
+ root: twMerge(
+ mergedTheme.host.base,
+ colorToTheme(mergedTheme.host.color, this.state.color())
+ ),
+ },
+ };
+ });
+
+ /**
+ * @internal
+ */
+ readonly state = flowbiteTableState(this);
+}
diff --git a/libs/flowbite-angular/table/src/table/theme.ts b/libs/flowbite-angular/table/src/table/theme.ts
new file mode 100644
index 00000000..ab6378db
--- /dev/null
+++ b/libs/flowbite-angular/table/src/table/theme.ts
@@ -0,0 +1,48 @@
+import type { ColorToTheme, FlowbiteColors } from 'flowbite-angular';
+import { createTheme } from 'flowbite-angular';
+
+export interface FlowbiteTableColors
+ extends Pick {
+ [key: string]: ColorToTheme;
+}
+
+export interface FlowbiteTableTheme {
+ host: FlowbiteTableHostTheme;
+}
+
+export interface FlowbiteTableHostTheme {
+ base: string;
+ color: FlowbiteTableColors;
+}
+
+export const flowbiteTableTheme: FlowbiteTableTheme = createTheme({
+ host: {
+ base: 'w-full text-left text-sm',
+ color: {
+ default: {
+ light: 'text-gray-500',
+ dark: 'dark:text-gray-400',
+ },
+ info: {
+ light: 'text-gray-500',
+ dark: 'dark:text-gray-400',
+ },
+ failure: {
+ light: 'text-gray-500',
+ dark: 'dark:text-gray-400',
+ },
+ success: {
+ light: 'text-gray-500',
+ dark: 'dark:text-gray-400',
+ },
+ warning: {
+ light: 'text-gray-500',
+ dark: 'dark:text-gray-400',
+ },
+ primary: {
+ light: 'text-gray-500',
+ dark: 'dark:text-gray-400',
+ },
+ },
+ },
+});
diff --git a/libs/tools/src/generators/component/files/component/__directoryName__/src/__fileName__/__fileName__-state.ts.template b/libs/tools/src/generators/component/files/component/__directoryName__/src/__fileName__/__fileName__-state.ts.template
index c6e1e21c..56b361ec 100644
--- a/libs/tools/src/generators/component/files/component/__directoryName__/src/__fileName__/__fileName__-state.ts.template
+++ b/libs/tools/src/generators/component/files/component/__directoryName__/src/__fileName__/__fileName__-state.ts.template
@@ -8,6 +8,6 @@ import {
} from 'ng-primitives/state';
export const Flowbite<%= className %>StateToken = createStateToken<<%= className %>>('Flowbite <%= className %>');
-export const provideFlowbite<%= className %>State = createStateProvider(<%= className %>StateToken);
-export const injectFlowbite<%= className %>State = createStateInjector(<%= className %>StateToken);
-export const flowbite<%= className %>State = createState(<%= className %>StateToken);
+export const provideFlowbite<%= className %>State = createStateProvider(Flowbite<%= className %>StateToken);
+export const injectFlowbite<%= className %>State = createStateInjector(Flowbite<%= className %>StateToken);
+export const flowbite<%= className %>State = createState(Flowbite<%= className %>StateToken);
diff --git a/tsconfig.base.json b/tsconfig.base.json
index d47b1cb9..1e19f5dd 100644
--- a/tsconfig.base.json
+++ b/tsconfig.base.json
@@ -88,6 +88,7 @@
"flowbite-angular/pagination": ["libs/flowbite-angular/pagination/src/index.ts"],
"flowbite-angular/sidebar": ["libs/flowbite-angular/sidebar/src/index.ts"],
"flowbite-angular/tab": ["libs/flowbite-angular/tab/src/index.ts"],
+ "flowbite-angular/table": ["libs/flowbite-angular/table/src/index.ts"],
"flowbite-angular/theme-toggle": ["libs/flowbite-angular/theme-toggle/src/index.ts"],
"flowbite-angular/tooltip": ["libs/flowbite-angular/tooltip/src/index.ts"]
}